Revert "修复实例页长时间后不自动刷新:回前台强制拉数、SSE假连接兜底、快照请求超时防卡死。"

This reverts commit dbf935a570.
This commit is contained in:
dekun
2026-08-12 22:43:15 +08:00
parent dbf935a570
commit 5ad22a57da
4 changed files with 16 additions and 87 deletions
+7 -47
View File
@@ -1,17 +1,12 @@
/** /**
* embed 壳:SSE 收到后台 tick 后拉 JSON 快照更新 DOM. * embed 壳:SSE 收到后台 tick 后拉 JSON 快照更新 DOM,切换 tab 不再重复请求 HTML.
* 同时为 standalone/embed 提供:回前台强制刷新、SSE 假连接兜底.
*/ */
(function (global) { (function (global) {
let liveEventSource = null; let liveEventSource = null;
let liveReconnectTimer = null; let liveReconnectTimer = null;
let localLiveVersion = -1; let localLiveVersion = -1;
let sseConnected = false; let sseConnected = false;
let lastLiveEventAt = 0;
let refreshTimer = null; let refreshTimer = null;
let pendingWhileHidden = false;
/** 超过该毫秒无 live 事件则视为断流,允许 interval 兜底轮询 */
const LIVE_STALE_MS = 45000;
function isEmbedShell() { function isEmbedShell() {
return document.body && document.body.getAttribute("data-embed-shell") === "1"; return document.body && document.body.getAttribute("data-embed-shell") === "1";
@@ -35,37 +30,20 @@
if (tab === "options" && global.OptionsPanelLive && typeof global.OptionsPanelLive.refreshSoft === "function") { if (tab === "options" && global.OptionsPanelLive && typeof global.OptionsPanelLive.refreshSoft === "function") {
global.OptionsPanelLive.refreshSoft(options); global.OptionsPanelLive.refreshSoft(options);
} }
// 数据看板自有 SSE + 快照,不跟 embed live tick 重拉.
} }
function scheduleRefresh(opts) { function scheduleRefresh(opts) {
if (document.hidden) {
pendingWhileHidden = true;
return;
}
if (refreshTimer) return; if (refreshTimer) return;
const options = opts || {}; const options = opts || {};
refreshTimer = setTimeout(function () { refreshTimer = setTimeout(function () {
refreshTimer = null; refreshTimer = null;
if (document.hidden) { if (document.hidden) return;
pendingWhileHidden = true;
return;
}
pendingWhileHidden = false;
refreshTabData(currentTab(), { silent: true, force: !!options.force }); refreshTabData(currentTab(), { silent: true, force: !!options.force });
}, 80); }, 80);
} }
function kickRefresh(opts) {
pendingWhileHidden = false;
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = null;
}
refreshTabData(currentTab(), opts || { silent: true, force: true });
}
function onLiveEvent(data) { function onLiveEvent(data) {
lastLiveEventAt = Date.now();
const reason = data && data.reason; const reason = data && data.reason;
const ver = Number(data && data.live_version) || 0; const ver = Number(data && data.live_version) || 0;
if (!ver) return; if (!ver) return;
@@ -81,9 +59,7 @@
function closeLiveStream() { function closeLiveStream() {
if (liveEventSource) { if (liveEventSource) {
try { liveEventSource.close();
liveEventSource.close();
} catch (_) {}
liveEventSource = null; liveEventSource = null;
} }
if (liveReconnectTimer) { if (liveReconnectTimer) {
@@ -104,7 +80,6 @@
}); });
liveEventSource.onopen = function () { liveEventSource.onopen = function () {
sseConnected = true; sseConnected = true;
lastLiveEventAt = Date.now();
}; };
liveEventSource.onerror = function () { liveEventSource.onerror = function () {
sseConnected = false; sseConnected = false;
@@ -115,23 +90,7 @@
}; };
} }
function isConnectedFresh() {
if (!sseConnected || !liveEventSource) return false;
if (!lastLiveEventAt) return false;
return Date.now() - lastLiveEventAt < LIVE_STALE_MS;
}
function startLive() { function startLive() {
document.addEventListener("visibilitychange", function () {
if (document.hidden) return;
if (isEmbedShell()) {
if (!isConnectedFresh()) connectLiveStream();
}
kickRefresh({ silent: true, force: true });
});
window.addEventListener("pageshow", function (ev) {
if (ev.persisted) kickRefresh({ silent: true, force: true });
});
if (!isEmbedShell()) return; if (!isEmbedShell()) return;
connectLiveStream(); connectLiveStream();
} }
@@ -139,8 +98,9 @@
global.InstanceLive = { global.InstanceLive = {
start: startLive, start: startLive,
refreshTabData: refreshTabData, refreshTabData: refreshTabData,
kickRefresh: kickRefresh, isConnected: function () {
isConnected: isConnectedFresh, return sseConnected;
},
}; };
if (document.readyState === "loading") { if (document.readyState === "loading") {
+4 -19
View File
@@ -1173,17 +1173,6 @@ function accountSnapshotFundingMissing(data){
return !hasFunding && !hasTotal && !hasTrading; return !hasFunding && !hasTotal && !hasTrading;
} }
let accountSnapshotRetryCount = 0; let accountSnapshotRetryCount = 0;
let accountSnapshotInflight = false;
let priceSnapshotInflight = false;
function fetchJsonWithTimeout(url, timeoutMs) {
const ms = timeoutMs != null ? timeoutMs : 25000;
const ac = new AbortController();
const timer = setTimeout(function () { ac.abort(); }, ms);
return fetch(url, { signal: ac.signal, credentials: "same-origin" })
.then(function (r) { return r.json(); })
.finally(function () { clearTimeout(timer); });
}
function applyAccountSnapshot(data){ function applyAccountSnapshot(data){
if(!data || typeof data !== "object") return; if(!data || typeof data !== "object") return;
if(typeof data.show_perp_funds !== "undefined"){ if(typeof data.show_perp_funds !== "undefined"){
@@ -1274,10 +1263,8 @@ function applyAccountSnapshot(data){
} }
function refreshAccountSnapshot(opts){ function refreshAccountSnapshot(opts){
const options = opts || {}; const options = opts || {};
if(accountSnapshotInflight && !options.force) return;
accountSnapshotInflight = true;
const qs = options.force ? "?force=1" : ""; const qs = options.force ? "?force=1" : "";
fetchJsonWithTimeout("/api/account_snapshot" + qs, 25000).then(data=>{ fetch("/api/account_snapshot" + qs).then(r=>r.json()).then(data=>{
applyAccountSnapshot(data); applyAccountSnapshot(data);
if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){ if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){
accountSnapshotRetryCount += 1; accountSnapshotRetryCount += 1;
@@ -1290,7 +1277,7 @@ function refreshAccountSnapshot(opts){
accountSnapshotRetryCount += 1; accountSnapshotRetryCount += 1;
setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount);
} }
}).finally(()=>{ accountSnapshotInflight = false; }); });
} }
const orderSymbolEl = document.getElementById("order-symbol"); const orderSymbolEl = document.getElementById("order-symbol");
@@ -1432,10 +1419,8 @@ refreshOrderDefaults();
if(typeof initOrderEntryModelSelect === "function") initOrderEntryModelSelect(); if(typeof initOrderEntryModelSelect === "function") initOrderEntryModelSelect();
refreshPriceSnapshotConditional(); refreshPriceSnapshotConditional();
function refreshPriceSnapshotConditional(){ function refreshPriceSnapshotConditional(){
if(priceSnapshotInflight) return;
priceSnapshotInflight = true;
const page = document.body.getAttribute("data-page") || ""; const page = document.body.getAttribute("data-page") || "";
fetchJsonWithTimeout("/api/price_snapshot", 25000).then(data=>{ fetch("/api/price_snapshot").then(r=>r.json()).then(data=>{
const updatedEl = document.getElementById("price-last-updated"); const updatedEl = document.getElementById("price-last-updated");
if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at; if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at;
if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){ if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){
@@ -1489,7 +1474,7 @@ function refreshPriceSnapshotConditional(){
} else if (typeof data.options_unrealized_pnl !== "undefined") { } else if (typeof data.options_unrealized_pnl !== "undefined") {
paintRealtimePnlFromSnapshot(data); paintRealtimePnlFromSnapshot(data);
} }
}).catch(()=>{}).finally(()=>{ priceSnapshotInflight = false; }); }).catch(()=>{});
} }
function formatLiveHoldDurationFromMs(openedMs, nowMs){ function formatLiveHoldDurationFromMs(openedMs, nowMs){
if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—"; if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—";
+1 -1
View File
@@ -171,7 +171,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
window.__INSTANCE_DISPLAY__ = {{ display | tojson }}; window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
</script> </script>
<script src="/static/instance_settings_prefs.js?v=21"></script> <script src="/static/instance_settings_prefs.js?v=21"></script>
<script src="/static/instance_live.js?v=7"></script> <script src="/static/instance_live.js?v=6"></script>
<script src="/static/instance_embed.js?v=31"></script> <script src="/static/instance_embed.js?v=31"></script>
<script src="/static/instance_mobile_nav.js?v=2"></script> <script src="/static/instance_mobile_nav.js?v=2"></script>
</body> </body>
+4 -20
View File
@@ -1654,17 +1654,6 @@ function accountSnapshotFundingMissing(data){
return !hasFunding && !hasTotal && !hasTrading; return !hasFunding && !hasTotal && !hasTrading;
} }
let accountSnapshotRetryCount = 0; let accountSnapshotRetryCount = 0;
let accountSnapshotInflight = false;
let priceSnapshotInflight = false;
function fetchJsonWithTimeout(url, timeoutMs) {
const ms = timeoutMs != null ? timeoutMs : 25000;
const ac = new AbortController();
const timer = setTimeout(function () { ac.abort(); }, ms);
return fetch(url, { signal: ac.signal, credentials: "same-origin" })
.then(function (r) { return r.json(); })
.finally(function () { clearTimeout(timer); });
}
function applyAccountSnapshot(data){ function applyAccountSnapshot(data){
if(!data || typeof data !== "object") return; if(!data || typeof data !== "object") return;
if(typeof data.show_perp_funds !== "undefined"){ if(typeof data.show_perp_funds !== "undefined"){
@@ -1764,10 +1753,8 @@ function applyAccountSnapshot(data){
} }
function refreshAccountSnapshot(opts){ function refreshAccountSnapshot(opts){
const options = opts || {}; const options = opts || {};
if(accountSnapshotInflight && !options.force) return;
accountSnapshotInflight = true;
const qs = options.force ? "?force=1" : ""; const qs = options.force ? "?force=1" : "";
fetchJsonWithTimeout("/api/account_snapshot" + qs, 25000).then(data=>{ fetch("/api/account_snapshot" + qs).then(r=>r.json()).then(data=>{
applyAccountSnapshot(data); applyAccountSnapshot(data);
if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){ if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){
accountSnapshotRetryCount += 1; accountSnapshotRetryCount += 1;
@@ -1780,7 +1767,7 @@ function refreshAccountSnapshot(opts){
accountSnapshotRetryCount += 1; accountSnapshotRetryCount += 1;
setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount);
} }
}).finally(()=>{ accountSnapshotInflight = false; }); });
} }
{% if ui_open_guard_enabled %} {% if ui_open_guard_enabled %}
@@ -1938,10 +1925,8 @@ refreshOrderDefaults();
refreshPriceSnapshotConditional(); refreshPriceSnapshotConditional();
setInterval(refreshAccountSnapshot, {{ balance_refresh_seconds * 1000 }}); setInterval(refreshAccountSnapshot, {{ balance_refresh_seconds * 1000 }});
function refreshPriceSnapshotConditional(){ function refreshPriceSnapshotConditional(){
if(priceSnapshotInflight) return;
priceSnapshotInflight = true;
const page = document.body.getAttribute("data-page") || ""; const page = document.body.getAttribute("data-page") || "";
fetchJsonWithTimeout("/api/price_snapshot", 25000).then(data=>{ fetch("/api/price_snapshot").then(r=>r.json()).then(data=>{
const updatedEl = document.getElementById("price-last-updated"); const updatedEl = document.getElementById("price-last-updated");
if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at; if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at;
if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){ if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){
@@ -2015,7 +2000,7 @@ function refreshPriceSnapshotConditional(){
} else if (typeof data.options_unrealized_pnl !== "undefined") { } else if (typeof data.options_unrealized_pnl !== "undefined") {
paintRealtimePnlFromSnapshot(data); paintRealtimePnlFromSnapshot(data);
} }
}).catch(()=>{}).finally(()=>{ priceSnapshotInflight = false; }); }).catch(()=>{});
} }
function formatLiveHoldDurationFromMs(openedMs, nowMs){ function formatLiveHoldDurationFromMs(openedMs, nowMs){
if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—"; if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—";
@@ -2048,7 +2033,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }})
<script src="/static/records_review_page.js?v=4"></script> <script src="/static/records_review_page.js?v=4"></script>
<script src="/static/options_expiry_countdown.js?v=1"></script> <script src="/static/options_expiry_countdown.js?v=1"></script>
<script src="/static/instance_dashboard.js?v=5"></script> <script src="/static/instance_dashboard.js?v=5"></script>
<script src="/static/instance_live.js?v=7"></script>
<script src="/static/account_ledger.js?v=1"></script> <script src="/static/account_ledger.js?v=1"></script>
<script> <script>
window.__INSTANCE_DISPLAY__ = {{ display | tojson }}; window.__INSTANCE_DISPLAY__ = {{ display | tojson }};