应优先监听 freeze 事件处理系统回收:此时 js 可同步执行、dom 可读、定时器未停摆,仅做清定时器、取消请求、存关键状态三件事;pageshow+persisted===false 需结合 localstorage 时间戳、url 参数和 navigation type 判定丢弃重建;visibilitychange 仅用于轻量暂停,不可误作资源释放依据。

区分“被动隐藏”(如用户切到其他标签、最小化窗口)和“系统回收”(如后台冻结或丢弃),关键不在于猜状态,而在于捕获浏览器明确发出的信号。Page Lifecycle API 提供了唯一可信赖的边界事件:freeze 表示即将被冻结,pageshow + persisted === false 且无缓存痕迹则高度提示已被丢弃。中间的 hidden 状态既不安全也不充分,不能作为资源释放或状态保存的依据。
用 freeze 事件锚定“系统回收前的最后一刻”
freeze 是 JS 还能同步执行、DOM 可读、定时器尚未停摆的最终时机,它只在系统准备冻结页面时触发,与用户行为无关。只要监听到它,就代表浏览器已决定干预——不是“可能”,而是“马上”。
- 必须使用
{ once: true }绑定,避免重复清理或写入失败 - 在此回调中只做三件事:清除所有定时器(
clearInterval/clearTimeout)、取消未完成请求(用AbortController)、持久化关键状态(localStorage.setItem()) - 禁止发起新请求、修改 DOM 或调用异步存储(如 indexedDB),这些操作大概率被静默截断
用 pageshow + persisted 和辅助信号识别“已丢弃后重建”
页面被 discard 后,浏览器会彻底销毁 JS 上下文。用户重新打开时,是一次全新加载,此时 pageshow 事件会触发,且 event.persisted === false。但这本身不等于“曾被丢弃”,需交叉验证:
- 检查
localStorage中上次保存的时间戳,若距当前超过 3–5 分钟,基本可判定非正常挂起,而是被丢弃 - 读取 URL 参数(如
?_reloaded=1),该参数应在 freeze 或 pagehide(persisted=true) 中主动写入,作为“我曾存活过”的凭证 - 调用
performance.getEntriesByType('navigation')[0]?.type,若为'reload'或'navigate',配合时间差,进一步佐证冷启动
对“被动隐藏”保持克制,只做轻量暂停
visibilitychange 触发时 document.visibilityState === 'hidden',仅说明页面不可见,不代表资源将被回收。很多场景(如桌面多窗口切换、画中画播放)下页面长期 hidden 却未冻结,过早释放会导致体验断裂。
- 适合在此阶段做的只有:暂停视频/音频、停止 Canvas 动画、暂停轮询(但保留定时器 ID)
- 不要清空 localStorage、不取消请求、不重置表单草稿——这些动作应留给 freeze 或 pagehide(persisted=true)
- 可结合
document.hasFocus() === false辅助判断是否失去交互权,但仍不能等同于系统干预
智能补写 = 区分场景 + 原子操作 + 防重入
所谓“补写”,不是把所有数据重刷一遍,而是按需恢复最小必要现场:
- 冷启动(discard 后重建):从 localStorage 拉取最近一次 freeze 保存的快照,仅还原 scrollY、编辑框内容、筛选条件等用户可感知字段
- 热恢复(bfcache 或 resume):不重载数据,只校验定时器是否失效、检查 token 是否过期、微调 UI 状态(如按钮 loading 态需清除)
- 所有恢复逻辑加防抖(如延迟 100ms 执行)并标记
__restored标志位,避免 resume 和 pageshow 先后触发造成重复还原
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










