你以为开了 PWA 导航就快了?每次多等 50ms 不是代码的错
每次用户点链接,浏览器要干三件事:加载主文档、启动 ServiceWorker、在 SW 的 fetch 事件里决定怎么响应。
问题就出在”启动 ServiceWorker”这一步。
SW 启动不是即时的。Chrome DevTools 数据显示,一般设备约 50ms,冷启或低端机能到 250ms,极端情况超 500ms。这段时间里,浏览器是在等 SW 启动完,才发网络请求。用户看到的就是:点了链接→等 SW→才看到网络请求→拿到页面。
这就是为什么有时候开了 PWA,首页反而比不开慢。
以前怎么解?手动开 NavigationPreload
Jake Archibald 早在 2017 年就在 web.dev 写过 NavigationPreload:让浏览器在 SW 启动的同时发网络请求,两件事并行。
但这需要改两处代码:
// 1. 注册时开启
navigator.serviceWorker.register("/sw.js").then(r => {
r.navigationPreload.enable();
});
// 2. SW 里消费 preloadResponse
addEventListener("fetch", event => {
if (event.request.destination === "document") {
event.respondWith(
event.preloadResponse || fetch(event.request)
);
}
});
很多团队觉得这门槛高,宁可忍受这几百毫秒的阻塞。
Chrome 154 自动帮你做了这件事
Chrome 154 带来了 ServiceWorkerAutoPreload,本质上是自动版 NavigationPreload:浏览器在 SW 启动的同时自动发导航请求,不需要你改一行代码,SW 里也不需要处理 preloadResponse。
效果和手动开 NavigationPreload 一样:SW 启动和网络请求并行,省掉等待时间。
从 WICG 的 explainer 来看,这个行为是默认开启的,Chrome 会在所有支持该协议的导航请求上自动并行。只有企业管理员通过 ServiceWorkerAutoPreloadEnabled 策略禁用它(设为 Disabled 时,浏览器会退回到等 SW 启动完才发请求的旧行为)。
实测数据:从 500ms 到 250ms
Jake Archibald 2017 年的演示里,故意在 SW 里加了 500ms 启动延迟:
- 没 NavigationPreload:SW 启动 500ms → 才发网络请求 → 页面才来,总耗时约 700ms
- 有 NavigationPreload:SW 启动 500ms 同时网络请求已在路上 → 总耗时降到约 400ms
实际生产环境没这么极端,但每次导航省 50-250ms,对 INP 和 LCP 的影响是实打实的。
适合谁?以及什么时候别用
适合:
- SW 用 NetworkFirst 策略处理导航请求的 PWA
- 没在预缓存 HTML 的 SPA(否则 preload 拉一遍又不用,白跑一次网络)
别用(会被拖慢):
- 已用 Workbox 全面预缓存 HTML 的站
- SW 逻辑极轻、启动本来就快(并行收益不大)
判断方法:下次打开 DevTools 的 Network 面板,清掉缓存硬刷新,看第一个 document 请求的 timing——如果有较长的「Waiting for ServiceWorker」时间,这个改动对你就有价值。
三步下一步
- 验证:Chrome 154+ 打开 DevTools → Network → 清缓存硬刷新 → 看 document 请求的「Starting Worker」时间有没有变短
- 确认 SW 逻辑:如果 SW 用 NetworkFirst 但没开 preload,手动加上
navigationPreload.enable()+event.preloadResponse,Chrome 154 会自动给这段再加一层保险 - 弱网实测:关 4G 限速到 Slow 3G,对比 Chrome 153 和 154 的首屏时间差
Chrome 154 正在 stepped rollout,稳定版预计 9 月 9 日全量推送。不用改代码,等着就是了。
评论区
登录后可评论。