diff --git a/lib/common/static/instance_live.js b/lib/common/static/instance_live.js index 23aa5cf..f51b3be 100644 --- a/lib/common/static/instance_live.js +++ b/lib/common/static/instance_live.js @@ -1,17 +1,12 @@ /** - * embed 壳:SSE 收到后台 tick 后拉 JSON 快照更新 DOM. - * 同时为 standalone/embed 提供:回前台强制刷新、SSE 假连接兜底. + * embed 壳:SSE 收到后台 tick 后拉 JSON 快照更新 DOM,切换 tab 不再重复请求 HTML. */ (function (global) { let liveEventSource = null; let liveReconnectTimer = null; let localLiveVersion = -1; let sseConnected = false; - let lastLiveEventAt = 0; let refreshTimer = null; - let pendingWhileHidden = false; - /** 超过该毫秒无 live 事件则视为断流,允许 interval 兜底轮询 */ - const LIVE_STALE_MS = 45000; function isEmbedShell() { return document.body && document.body.getAttribute("data-embed-shell") === "1"; @@ -35,37 +30,20 @@ if (tab === "options" && global.OptionsPanelLive && typeof global.OptionsPanelLive.refreshSoft === "function") { global.OptionsPanelLive.refreshSoft(options); } + // 数据看板自有 SSE + 快照,不跟 embed live tick 重拉. } function scheduleRefresh(opts) { - if (document.hidden) { - pendingWhileHidden = true; - return; - } if (refreshTimer) return; const options = opts || {}; refreshTimer = setTimeout(function () { refreshTimer = null; - if (document.hidden) { - pendingWhileHidden = true; - return; - } - pendingWhileHidden = false; + if (document.hidden) return; refreshTabData(currentTab(), { silent: true, force: !!options.force }); }, 80); } - function kickRefresh(opts) { - pendingWhileHidden = false; - if (refreshTimer) { - clearTimeout(refreshTimer); - refreshTimer = null; - } - refreshTabData(currentTab(), opts || { silent: true, force: true }); - } - function onLiveEvent(data) { - lastLiveEventAt = Date.now(); const reason = data && data.reason; const ver = Number(data && data.live_version) || 0; if (!ver) return; @@ -81,9 +59,7 @@ function closeLiveStream() { if (liveEventSource) { - try { - liveEventSource.close(); - } catch (_) {} + liveEventSource.close(); liveEventSource = null; } if (liveReconnectTimer) { @@ -104,7 +80,6 @@ }); liveEventSource.onopen = function () { sseConnected = true; - lastLiveEventAt = Date.now(); }; liveEventSource.onerror = function () { 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() { - 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; connectLiveStream(); } @@ -139,8 +98,9 @@ global.InstanceLive = { start: startLive, refreshTabData: refreshTabData, - kickRefresh: kickRefresh, - isConnected: isConnectedFresh, + isConnected: function () { + return sseConnected; + }, }; if (document.readyState === "loading") { diff --git a/lib/instance/templates/embed_boot_scripts.html b/lib/instance/templates/embed_boot_scripts.html index 47581fb..8241233 100644 --- a/lib/instance/templates/embed_boot_scripts.html +++ b/lib/instance/templates/embed_boot_scripts.html @@ -1173,17 +1173,6 @@ function accountSnapshotFundingMissing(data){ return !hasFunding && !hasTotal && !hasTrading; } 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){ if(!data || typeof data !== "object") return; if(typeof data.show_perp_funds !== "undefined"){ @@ -1274,10 +1263,8 @@ function applyAccountSnapshot(data){ } function refreshAccountSnapshot(opts){ const options = opts || {}; - if(accountSnapshotInflight && !options.force) return; - accountSnapshotInflight = true; 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); if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){ accountSnapshotRetryCount += 1; @@ -1290,7 +1277,7 @@ function refreshAccountSnapshot(opts){ accountSnapshotRetryCount += 1; setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); } - }).finally(()=>{ accountSnapshotInflight = false; }); + }); } const orderSymbolEl = document.getElementById("order-symbol"); @@ -1432,10 +1419,8 @@ refreshOrderDefaults(); if(typeof initOrderEntryModelSelect === "function") initOrderEntryModelSelect(); refreshPriceSnapshotConditional(); function refreshPriceSnapshotConditional(){ - if(priceSnapshotInflight) return; - priceSnapshotInflight = true; 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"); if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at; if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){ @@ -1489,7 +1474,7 @@ function refreshPriceSnapshotConditional(){ } else if (typeof data.options_unrealized_pnl !== "undefined") { paintRealtimePnlFromSnapshot(data); } - }).catch(()=>{}).finally(()=>{ priceSnapshotInflight = false; }); + }).catch(()=>{}); } function formatLiveHoldDurationFromMs(openedMs, nowMs){ if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—"; diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index 619c2bc..07cbbe4 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -171,7 +171,7 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj window.__INSTANCE_DISPLAY__ = {{ display | tojson }}; - + diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index 89efc5a..0153cf4 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -1654,17 +1654,6 @@ function accountSnapshotFundingMissing(data){ return !hasFunding && !hasTotal && !hasTrading; } 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){ if(!data || typeof data !== "object") return; if(typeof data.show_perp_funds !== "undefined"){ @@ -1764,10 +1753,8 @@ function applyAccountSnapshot(data){ } function refreshAccountSnapshot(opts){ const options = opts || {}; - if(accountSnapshotInflight && !options.force) return; - accountSnapshotInflight = true; 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); if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){ accountSnapshotRetryCount += 1; @@ -1780,7 +1767,7 @@ function refreshAccountSnapshot(opts){ accountSnapshotRetryCount += 1; setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); } - }).finally(()=>{ accountSnapshotInflight = false; }); + }); } {% if ui_open_guard_enabled %} @@ -1938,10 +1925,8 @@ refreshOrderDefaults(); refreshPriceSnapshotConditional(); setInterval(refreshAccountSnapshot, {{ balance_refresh_seconds * 1000 }}); function refreshPriceSnapshotConditional(){ - if(priceSnapshotInflight) return; - priceSnapshotInflight = true; 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"); if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at; if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){ @@ -2015,7 +2000,7 @@ function refreshPriceSnapshotConditional(){ } else if (typeof data.options_unrealized_pnl !== "undefined") { paintRealtimePnlFromSnapshot(data); } - }).catch(()=>{}).finally(()=>{ priceSnapshotInflight = false; }); + }).catch(()=>{}); } function formatLiveHoldDurationFromMs(openedMs, nowMs){ if(openedMs == null || openedMs === "" || !Number.isFinite(Number(openedMs))) return "—"; @@ -2048,7 +2033,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }}) -