作为性能修复手段的导航预加载:在 service worker 启动的同时发出网络请求
一句话: 若不启用导航预加载,service worker 的启动时间会横在导航网络请求前面;根据 web.dev,启用预加载后,浏览器会在 service worker 仍在启动时就发出网络请求,因此启动时 间不再阻塞网络请求。
延迟从何而来
Section titled “延迟从何而来”对于一个由带有 fetch 事件处理器的 service worker 控制的页面,浏览器必须向该 worker
派发这个事件并等待响应——如果 worker 尚未运行,就意味着要先启动它。根据 web.dev 的数据,这段启动时间取决于设备和当前
状况:桌面端通常约 50ms,移动端更接近 250ms,在缓慢或 CPU 受限的设备上甚至可能超过
500ms。如果不启用导航预加载,导航的网络请求要等到 worker 启动完毕并开始执行 fetch
处理器之后才会发出——启动时间因此被直接叠加到获取响应所需的时间上。
与 TTFB 的关联
Section titled “与 TTFB 的关联”Time to First Byte 包含浏览器在响应到达前,检查是否有活跃的 service worker 能提供匹配 响应所花的时间。当这项检查需要一次冷启动时,启动延迟就成了 TTFB 的一部分。根据 web.dev, 导航预加载会在 service worker 启动的同时就发出网络请求;启动延迟依然存在,但它不再阻塞 网络请求。
启用方式与使用结果
Section titled “启用方式与使用结果”addEventListener('activate', (event) => { event.waitUntil( (async () => { if ('navigationPreload' in self.registration) { await self.registration.navigationPreload.enable(); } else { // 不支持:无需启用。下面的 fetch 处理器依旧能工作,只是要等 worker // 启动完毕后导航请求才会发出——和没有这段代码时的行为一样。 return; } })(), );});
addEventListener('fetch', (event) => { event.respondWith( (async () => { const preload = await event.preloadResponse; if (preload) return preload; return fetch(event.request); })(), );});'navigationPreload' in self.registration 即为特性检测写法;
当该请求未触发预加载时(例如非 GET 或非导航请求),event.preloadResponse 会解析为
undefined,因此处理器必须始终回退到普通的 fetch()。MDN 自己的
FetchEvent.preloadResponse 示例用
event.waitUntil(preloadResponsePromise.catch(() => undefined)) 让已启动但未使用的预
加载请求保持存活,以免在处理器最终改为从缓存提供响应时它被取消。
根据 MDN,NavigationPreloadManager 需要安全上下文(HTTPS),自 2022 年 4 月起属于
Baseline 广泛可用。
何时它没有帮助
Section titled “何时它没有帮助”导航预加载并非普遍有益。根据 web.dev,如果页面直接从 Cache Storage API 提供,service worker 的启动时间就不算显著问题,因为缓存中的响应本就无需等待网络即可获得——对这类响应 而言,预加载本要隐藏的那段延迟从一开始就不是瓶颈。
- 在采用预加载之前,先测量你的导航响应究竟来自缓存还是网络——完全预缓存的 app shell 从中获益较少。
- 在
activate中启用它,并以if ('navigationPreload' in self.registration)作为保护。 - 始终 await
event.preloadResponse,并在其解析为undefined时回退到fetch()。 - 按照 MDN 的
FetchEvent.preloadResponse示例,用event.waitUntil()让已启动但 未使用的预加载请求保持存活,避免在你最终改为从缓存提供响应时它被取消。 - 如果预加载响应与普通响应可能不同,请在服务器上设置
Vary: Service-Worker-Navigation-Preload,以免缓存把两者混淆。
- 导航预加载(Service Worker API 参考) ——
本文将其作为性能修复手段来讨论的完整
NavigationPreloadManagerAPI。 - 核心网页指标 —— 导航预加载直接针对的 TTFB,在更广泛的页面加载指标体系中所处的位置。