如何将已废弃的页面现场通过Page Lifecycle API还原?
- 内容介绍
- 文章标签
- 相关推荐
本文共计848个文字,预计阅读时间需要4分钟。
“废弃+状态本体无法被监听或捕获,它不是事件,而是
唯一可用线索:pageshow 事件 + persisted === false
当用户从任务管理器、后台或最近应用列表中重新打开一个曾被 discard 的 Tab,浏览器会发起全新导航(相当于刷新),此时触发 pageshow 事件,且 event.persisted === false。这和 Frozen 后 resume 的 persisted === true 完全相反。
但注意:persisted === false 不等于 discard,它只表示“这次不是从缓存恢复”,可能是用户手动刷新、跳转回来,或真被 discard 后重建。你需要交叉验证:
- 检查 localStorage 中是否存有上一次保存的状态时间戳,若距当前时间 > 5 分钟,大概率已被 discard(Frozen 通常撑不过 2–3 分钟)
- 读取 URL 参数,比如 ?_reloaded=1 —— 这需要你在 freeze 或 pagehide 时主动写入,作为 discard 前的“最后呼救”
- 用
performance.getEntriesByType('navigation')[0]?.type查看导航类型,值为 'reload' 或 'navigate' 且配合其他信号,可增强判断可信度
真正能保存状态的时机只有两个
别等 discarded——它不可逆。必须在进入 Frozen 阶段前完成持久化,可靠窗口只有:
- freeze 事件:页面冻结前最后一刻,DOM 可读、JS 可执行,适合同步写入 localStorage 或 sessionStorage
- pagehide 且 event.persisted === true:说明浏览器计划缓存该页(bfcache 或 Frozen),也是安全保存点
在这两个时机里,你可以调用 localStorage.setItem() 存关键字段,例如:scrollY、activeTab、formValue。避免 indexedDB 写入(异步可能来不及)、禁止发起新 fetch 或修改 DOM。
还原逻辑必须区分冷启动与热恢复
用户回到页面时,你要立刻判断这次加载性质:
- 若
pageshow.persisted === false,且document.hasFocus() === true,同时 localStorage 中有较新的状态数据 → 视为 discard 后冷启动,应从存储中读取并手动 restore UI(如滚动到位置、填入表单、切换 tab) - 若
pageshow.persisted === true→ 是 bfcache/Frozen 恢复,DOM 和 JS 状态基本完整,无需重载,只需轻量校验(如检查 token 是否过期)
还原后,建议清除已恢复的状态标记(如删掉 localStorage 里的临时 key),防止下次 pageshow 重复执行。
document.wasDiscarded 只用于事后清理
document.wasDiscarded 是一个只读布尔值,仅在 discard 后首次 JS 执行时为 true,之后刷新即失效。它不触发事件,也不能预测 discard,只能用于“补救”:
- 清空旧的全局计数器、中断的轮询 ID、失效的 WebSocket 引用
- 重置播放器、Canvas、Web Audio 等不可恢复的上下文
- 避免把残留的旧状态和新拉取的数据混在一起处理
它不是还原的依据,而是还原完成后的收尾动作。
本文共计848个文字,预计阅读时间需要4分钟。
“废弃+状态本体无法被监听或捕获,它不是事件,而是
唯一可用线索:pageshow 事件 + persisted === false
当用户从任务管理器、后台或最近应用列表中重新打开一个曾被 discard 的 Tab,浏览器会发起全新导航(相当于刷新),此时触发 pageshow 事件,且 event.persisted === false。这和 Frozen 后 resume 的 persisted === true 完全相反。
但注意:persisted === false 不等于 discard,它只表示“这次不是从缓存恢复”,可能是用户手动刷新、跳转回来,或真被 discard 后重建。你需要交叉验证:
- 检查 localStorage 中是否存有上一次保存的状态时间戳,若距当前时间 > 5 分钟,大概率已被 discard(Frozen 通常撑不过 2–3 分钟)
- 读取 URL 参数,比如 ?_reloaded=1 —— 这需要你在 freeze 或 pagehide 时主动写入,作为 discard 前的“最后呼救”
- 用
performance.getEntriesByType('navigation')[0]?.type查看导航类型,值为 'reload' 或 'navigate' 且配合其他信号,可增强判断可信度
真正能保存状态的时机只有两个
别等 discarded——它不可逆。必须在进入 Frozen 阶段前完成持久化,可靠窗口只有:
- freeze 事件:页面冻结前最后一刻,DOM 可读、JS 可执行,适合同步写入 localStorage 或 sessionStorage
- pagehide 且 event.persisted === true:说明浏览器计划缓存该页(bfcache 或 Frozen),也是安全保存点
在这两个时机里,你可以调用 localStorage.setItem() 存关键字段,例如:scrollY、activeTab、formValue。避免 indexedDB 写入(异步可能来不及)、禁止发起新 fetch 或修改 DOM。
还原逻辑必须区分冷启动与热恢复
用户回到页面时,你要立刻判断这次加载性质:
- 若
pageshow.persisted === false,且document.hasFocus() === true,同时 localStorage 中有较新的状态数据 → 视为 discard 后冷启动,应从存储中读取并手动 restore UI(如滚动到位置、填入表单、切换 tab) - 若
pageshow.persisted === true→ 是 bfcache/Frozen 恢复,DOM 和 JS 状态基本完整,无需重载,只需轻量校验(如检查 token 是否过期)
还原后,建议清除已恢复的状态标记(如删掉 localStorage 里的临时 key),防止下次 pageshow 重复执行。
document.wasDiscarded 只用于事后清理
document.wasDiscarded 是一个只读布尔值,仅在 discard 后首次 JS 执行时为 true,之后刷新即失效。它不触发事件,也不能预测 discard,只能用于“补救”:
- 清空旧的全局计数器、中断的轮询 ID、失效的 WebSocket 引用
- 重置播放器、Canvas、Web Audio 等不可恢复的上下文
- 避免把残留的旧状态和新拉取的数据混在一起处理
它不是还原的依据,而是还原完成后的收尾动作。

