--- title: Page Lifecycle API 生命周期与资源管理:挂起、冻结与可见性实践 tags: [Page Lifecycle API, visibilitychange, pagehide, pageshow, freeze, resume, BFCache, 资源治理] description: 通过 Page Lifecycle API 管理页面可见性、挂起与冻结,安全暂停动画/网络与计算,兼容 BFCache 并显著降低耗电与CPU占用,附完整指标与测试策略。 categories: - 文章资讯 - 技术教程 --- # 背景与目标 - 浏览器在页面不可见、后台或即将冻结时会进行资源节流;主动配合生命周期事件可进一步降低资源消耗。 - 保持 BFCache 兼容(避免阻断返回前进缓存),改善回到页面时的恢复体验。 # 核心事件与语义 - `visibilitychange`:页面可见性变化;`document.visibilityState` 为 `hidden/visible`。 - `pagehide/pageshow`:页面进入/离开会话历史;`pagehide` 的 `event.persisted` 为 `true` 表示进入 BFCache。 - `freeze/resume`(Chrome):页面进入/恢复冻结态;可做最后状态持久化与轻量恢复。 # 资源治理:统一暂停与恢复 ```ts let rafId: number | null = null; let ws: WebSocket | null = null; let activeFetches = new Set(); function startLoop() { const loop = () => { rafId = requestAnimationFrame(loop); // 执行动画与轻量计算 }; if (rafId == null) rafId = requestAnimationFrame(loop); } function stopLoop() { if (rafId != null) { cancelAnimationFrame(rafId); rafId = null; } } function openWS() { if (!ws) ws = new WebSocket('wss://example.com'); } function closeWS() { if (ws) { ws.close(); ws = null; } } function fetchWithAbort(input: RequestInfo, init: RequestInit = {}) { const ac = new AbortController(); activeFetches.add(ac); const merged = { ...init, signal: ac.signal }; return fetch(input, merged).finally(() => activeFetches.delete(ac)); } function abortAllFetches() { activeFetches.forEach(ac => ac.abort()); } function saveState() { // 将必要的 UI/数据状态写入 IndexedDB/localStorage } function restoreState() { // 从持久层恢复必要状态,避免闪烁与不一致 } // 可见性变化:隐藏时暂停、可见时恢复 document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { stopLoop(); abortAllFetches(); // 视情况关闭WebSocket,或仅限速 closeWS(); } else { startLoop(); openWS(); } }); // 进入BFCache:不要破坏缓存;尽量停止外部副作用 window.addEventListener('pagehide', (e: PageTransitionEvent) => { saveState(); stopLoop(); // BFCache 允许在返回时快速恢复;避免使用 beforeunload 阻断 abortAllFetches(); closeWS(); }); // 从BFCache恢复或重新载入 window.addEventListener('pageshow', (e: PageTransitionEvent) => { restoreState(); startLoop(); openWS(); }); // Chrome 冻结/恢复事件(存在即用) document.addEventListener('freeze', () => { saveState(); stopLoop(); abortAllFetches(); closeWS(); }); document.addEventListener('resume', () => { restoreState(); startLoop(); openWS(); }); ``` # 设计要点与陷阱 - 避免 `beforeunload/unload`:这会使 BFCache 失效,导致返回页面变慢。 - 统一状态管理:将暂停/恢复逻辑封装为可复用模块,确保可见性、pagehide/freeze 路径一致。 - 计时器与动画:`requestAnimationFrame`/`setInterval` 在隐藏态常被节流;仍应主动取消,防止后台累积任务。 - 网络与并发:为所有 `fetch` 提供 `AbortController`;必要时关闭 WebSocket 或降低订阅频率。 - 媒体与图形:暂停 `

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部