perf(webui): gate list/system polling on tab visibility

两个兜底轮询(列表 reconcile、systemInfo 快轮询)的 tick 在 document.hidden 时跳过,
并监听 visibilitychange 在切回时立即补一次。后台标签页不再空转 fetch;实时状态本就
走 SSE(未门控),切回时立即刷新无空态闪烁。
This commit is contained in:
DrSmoothl
2026-07-02 15:02:13 +08:00
parent d17381a221
commit 99547e847e
+10 -2
View File
@@ -142,16 +142,21 @@ export function AppLayout() {
let cancelled = false;
const reconcileMs = Math.max(pollInterval * 10, 10_000);
const tick = async () => {
if (cancelled) return;
// Skip while the tab is hidden — SSE already carries live updates, and a
// backgrounded tab has no UI to refresh. Re-tick on becoming visible.
if (cancelled || document.hidden) return;
await Promise.all([refreshQqList(), refreshProcesses(), refreshConnections()]);
};
// Initial tick primes the lists before the SSE handshake completes
// (avoids a flash of empty state in the chrome).
tick();
const interval = setInterval(tick, reconcileMs);
const onVisible = () => { if (!document.hidden) void tick(); };
document.addEventListener('visibilitychange', onVisible);
return () => {
cancelled = true;
clearInterval(interval);
document.removeEventListener('visibilitychange', onVisible);
};
}, [pollInterval, refreshQqList, refreshProcesses, refreshConnections]);
@@ -164,14 +169,17 @@ export function AppLayout() {
if (pollInterval <= 0) return;
let cancelled = false;
const tick = async () => {
if (cancelled) return;
if (cancelled || document.hidden) return;
await refreshSystem();
};
tick();
const interval = setInterval(tick, pollInterval);
const onVisible = () => { if (!document.hidden) void tick(); };
document.addEventListener('visibilitychange', onVisible);
return () => {
cancelled = true;
clearInterval(interval);
document.removeEventListener('visibilitychange', onVisible);
};
}, [pollInterval, refreshSystem]);