discarded 状态无法监听,唯一可靠线索是 pageshow 中 persisted === false;需结合导航类型、时间戳等交叉验证,并在入口脚本顶部立即检查 document.wasDiscarded。

discarded 状态本身无法被监听或捕获,你永远收不到它的事件——所有试图监听 discarded 的代码都注定失效。真正能用的只有 pageshow 中的 persisted === false 这个线索,再结合时间戳、URL 参数和导航类型交叉判断是否曾被丢弃。
为什么不能监听 discarded 事件
浏览器进入 discarded 阶段时,JS 执行环境已被完全销毁:所有定时器清空、fetch 请求中断、beforeunload 和 pagehide 都不会触发,甚至 sendBeacon() 都发不出去。这不是一个“事件”,而是一个事后状态——你只能在用户重新打开该 Tab 时,通过加载上下文反推它曾被丢弃。
-
document.wasDiscarded是唯一暴露该状态的属性,但它只在页面从 discarded 恢复后的首次 JS 执行中为true,之后刷新即失效 - 没有
ondiscarded、没有addEventListener('discarded', ...),任何这类写法都不会生效 - 试图在
freeze或pagehide中“预测”即将 discarded 并做特殊处理,是徒劳的——冻结后撑多久由系统决定,不可控
pageshow.persisted === false 是唯一可靠线索
用户从任务管理器或后台切回一个被 discarded 后重建的页面时,浏览器会发起全新导航(等价于手动输入 URL 回车),此时 pageshow 触发且 event.persisted === false。注意:这和 Frozen 后 resume 的 persisted === true 完全相反。
- 必须监听
pageshow,而不是load或DOMContentLoaded——后者在 discarded 恢复时也会触发,但没提供persisted信息 - 仅凭
persisted === false不能直接断定是 discarded,需排除用户主动刷新、新开 Tab 等场景 - 建议组合验证:
performance.getEntriesByType('navigation')[0]?.type === 'navigate'且 URL 不含?_reloaded=1,同时localStorage.getItem('last_save_time')距当前 > 5 分钟
还原现场必须区分冷启动与热恢复
discard 后重建是冷启动:DOM 全新渲染、全局变量重置、所有事件监听器丢失;而 bfcache resume(persisted === true)是热恢复:DOM 和监听器都在,只是 JS 时间停摆。二者还原逻辑完全不同。
- 冷启动(discard 恢复):检查
document.wasDiscarded === true,立即清空旧缓存(如sessionStorage.removeItem('ui_state')),再从localStorage或服务端拉取快照,手动 restore 表单值、滚动位置、选中 tab - 热恢复(bfcache resume):不重置 DOM,只校验并续期定时器、重连长连接、更新过期数据,避免重复绑定监听器或双重发起请求
- 不要在
pageshow中无差别执行初始化逻辑——对热恢复来说,这等于把“暂停”当成“重启”,极易导致状态错乱
保存时机只能靠 freeze + pagehide(persisted=true)
想保住现场,唯一靠谱的时机是页面进入 Frozen 前,也就是 freeze 事件,以及兜底的 pagehide 且 event.persisted === true。这两个节点必须都覆盖,因为不同浏览器行为差异极大。
-
freeze中应同步写入localStorage.setItem('state', JSON.stringify(data)),避免 await 导致失败 -
pagehide中需加防抖:用performance.now()记录上次保存时间,200ms 内不再重复写入,防止和freeze冲突 - 保存内容必须轻量、可序列化:只存
window.scrollY、input.value、select.selectedIndex等原始值,绝不能存 DOM 节点、函数或 WebSocket 实例
最容易被忽略的是:discard 恢复后,document.wasDiscarded 只在第一行 JS 执行时有效——如果你把它放在某个异步回调里读取,大概率已经变成 false。必须在入口脚本最顶部就检查并处理。


















