十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

为 back/forward cache 优化页面:用 pagehide/pageshow 替代 unload,让返回导航近乎瞬时恢复

为 back/forward cache 优化页面:用 pagehide/pageshow 替代 unload,让返回导航近乎瞬时恢复 为 back/forward cache 优化页面用 pagehide/pageshow 替代 unload让返回导航近乎瞬时恢复【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-ChecklistBack/forward cache简称 bfcache是浏览器将用户离开的页面整体存入内存、在用户点击后退/前进按钮时直接从内存恢复的历史导航优化机制。本指南以 Front-End-Checklist 仓库中 Optimize pages for back/forward cache 规则 及其配套 Agent 技能定义 为核心讲清 bfcache 的命中条件、最常见的拦截器以及如何用pagehide/pageshow事件改写生命周期代码。读完你将掌握一套可落地的代码改造方案和验证流程让返回上一页从一次完整冷启动降级为一次内存级恢复。什么是 back/forward cache与 HTTP 缓存的本质区别Back/forward cache通常缩写为bfcache是浏览器的一项内存级优化当用户点击后退或前进按钮时浏览器直接从内存中恢复此前访问过的页面快照而不是重新向服务器发起请求、重新解析 HTML、重新执行应用启动序列。这一点与 HTTP 缓存有根本区别HTTP 缓存如Cache-Control、ETag缓存的是网络资源HTML、CSS、JS页面每次导航仍需重新下载资源、解析、执行并运行应用引导代码bfcache缓存的是完整的页面状态包括 JavaScript 堆内存、DOM 树、渲染状态和滚动位置。恢复时不再运行启动序列因此是最快的历史导航——根本不需要重新引导应用。在 Front-End-Checklist 中本规则被归类为performance大类、navigation子类优先级为 high、难度为 advanced、预估耗时 25 分钟见 back-forward-cache.mdx 的 frontmatter。它和同属性能类别的 speculation-rules 规则 互补bfcache 针对浏览器管理的历史导航用户按后退而 Speculation Rules API 针对下一次可能发生的导航提前 prefetch/prerender前者由浏览器接管后者由开发者声明式配置。为什么它重要用户为每次返回付费历史导航在真实使用中非常频繁尤其是移动端。页面命中 bfcache 时浏览器几乎瞬时恢复未命中时用户仅仅是回到几秒前看过的页面却要再付出一次完整的网络请求、HTML/CSS/JS 解析与 JavaScript 执行成本。命中 bfcache 带来的收益出自 规则文档 Why It Matters 章节后退/前进感知到的导航更快网络传输更少因为页面无需重建在慢速设备上体验更好完整应用启动代价高昂减少生命周期代码把每次导航都当作硬刷新而引发的意外回归。换句话说失去 bfcache 命中资格会让最常见的历史导航变得比应有的慢得多——这正是该规则在仓库中被标记为 high 优先级的原因。核心代码示例坏写法和好写法规则文档给出了一个对照示例是理解本规则最快的入口Code Example 章节// Bad: unload listeners commonly make a page ineligible for bfcache window.addEventListener(unload, () { navigator.sendBeacon(/analytics/leave) }) // Good: pagehide runs for normal unloads and bfcache attempts window.addEventListener(pagehide, () { navigator.sendBeacon(/analytics/leave) }) // Good: detect a restore and refresh only what is time-sensitive window.addEventListener(pageshow, async (event) { if (!event.persisted) return await refreshUnreadCount() closeTransientOverlays() })这个示例同时覆盖了三个关键知识点unload是头号拦截器——注册unload监听会让页面几乎必然失去 bfcache 资格pagehide是unload的替代品——它在正常卸载和 bfcache 尝试时都会触发适合放置发埋点、清理类逻辑pageshowevent.persisted是恢复检测的标准姿势——persisted为true说明页面是从 bfcache 恢复的此时应只刷新时效敏感的数据如未读数、临时浮层而不是整页重载。最佳实践逐条拆解规则文档的 Best Practices 章节给出了四条可执行的实践这里逐条结合机制细节展开。1. 永远不要使用unload如果只能做一处修改就改这一处。unload事件是最明确、最常见的 bfcache 拦截器。正确的替代方案是用pagehide做 teardown清理/上报工作用pageshow做恢复resume工作。这里的关键机制是pagehide在页面进入 bfcache 前也会触发所以原本放在unload里的navigator.sendBeacon(/analytics/leave)这类离开埋点移到pagehide后功能完全一致却不再阻塞缓存资格。2. 把从缓存恢复与全新加载区分对待用pageshow事件并检查event.persistedwindow.addEventListener(pageshow, (event) { if (event.persisted) { syncSessionExpiryBanner() refreshCsrfTokenIfNeeded() } })不要在每个恢复场景都盲目硬刷新hard-reload。只刷新会过期的状态例如认证/会话过期提示收件箱未读数短生命周期的 CSRF token。规则文档明确强调Do not blindly hard-reload on every restore. Refresh only the state that can become stale, such as auth warnings, inbox counts, or short-lived tokens.Best Practices 章节3. 让beforeunload保持条件化如果页面确实需要未保存更改的离开警告务必只在页面处于 dirty 状态时挂载监听保存完成后立即移除function toggleUnsavedChangesProtection(isDirty) { if (isDirty) { window.addEventListener(beforeunload, handleBeforeUnload) } else { window.removeEventListener(beforeunload, handleBeforeUnload) } }持久化挂载beforeunload会让恢复可靠性下降通常是页面没有精确跟踪 dirty 状态的信号。注意beforeunload与unload不同它本身不直接等于 bfcache 拦截器但无条件挂载会显著降低缓存资格因此也应保持条件化。4. 避免跨恢复的脆弱长生命周期工作从内存恢复的页面会继续此前挂起的任务。页面级生命周期代码应具备恢复韧性Best Practices 最后一条恢复时关闭瞬时 UI如抽屉drawer、弹层popover、过期的 toast重新校验短生命周期数据而不是假定内存副本仍然新鲜不要把重要清理工作只绑定在硬卸载行为上例如只放在unload中。通过/失败阈值如何判定页面是否达标规则文档定义了明确的判定标准Thresholds 章节通过该路由没有任何无条件unload监听且目标浏览器中后退导航从内存恢复通过时效敏感状态在pageshow.persisted true之后刷新且没有强制整页重载失败历史导航总是重建页面因为生命周期代码阻塞了 bfcache 资格。这一判定标准同时被写进了 Agent 技能 Quick Reference绝不添加unload监听、用pagehide/pageshow替代每次导航都重载的假设、在pageshow.persisted true时刷新时效状态、beforeunload保持条件化、在 DevTools 中验证资格而非臆断页面可缓存。浏览器差异与诊断以真实运行时为准规则文档的 Support Notes 特别提醒两点Support Notes 章节bfcache 行为因浏览器而异必须针对真实的目标浏览器矩阵验证不能假设某个浏览器内核的行为在所有地方都成立以浏览器的 bfcache 诊断工具为唯一事实来源某个路由是否可缓存、被什么拦截以 DevTools 中的 back/forward cache 面板为准。这条原则同样被写入 Agent 技能的aiContext审查时应检查实际的浏览器生命周期与恢复路径而不只是静态代码模式见 SKILL.md frontmatter。从仓库结构看这也是规则被做成供人类阅读的 .mdx 供 Agent 执行的 SKILL.md双层结构的原因——静态审查只能发现问题线索最终判定必须回到真实浏览器。例外情况合理但不滥用规则文档承认三类合理的例外Exceptions 章节某些路由确实需要条件化的beforeunload警告存在未保存数据时但页面一旦干净就应移除处理敏感或快速变化数据的页面可以在恢复时做定向重新校验——但这依然不能成为把每次恢复都强制整页重载的理由第三方库可能替你挂载生命周期监听器因此不要只信源码必须在浏览器中验证真实运行时行为。第三点是实践中最容易被忽视的你的代码干净不代表页面干净例如某些分析 SDK、聊天组件或反爬脚本会在内部注册unload/beforeunload监听。验证清单自动化与手动两手抓规则文档的 Verification 章节给出了完整的验收流程Verification 章节。自动化检查在代码库和构建产物中搜索addEventListener(unload或等价的 unload 挂钩运行 Lighthouse 或等效诊断工具确认路由上没有任何 unload-listener 警告。手动检查在浏览器中打开页面导航到第二个页面然后点击后退按钮若页面立即恢复且pageshow处理器报告event.persisted true则通过打开 DevTools用浏览器的 back/forward cache 工具检查该路由确认页面可缓存eligible并查看具体的拦截原因blockers。这套验证与仓库中该规则的分类结构一致——规则同时被用于人类审查代码搜索 Lighthouse和 Agent 审查Review route code, global listeners, analytics hooks, and contenteditable="false">【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表