Navigation Preload 通过并行发起原始网络请求解决首屏 HTML 的串行延迟,需显式调用 enable() 并容错处理,fetch 中仅对 document 请求安全使用 preloadResponse,配合预缓存和三级 fallback 才完整生效。

Navigation Preload 不是让 Service Worker 提前启动,而是让浏览器在 SW 启动的同时,并行发起原始网络请求。它专为解决首屏 HTML 加载时“等 SW 初始化”带来的串行延迟而设计,真正让导航不卡顿。
注册阶段必须显式启用
仅检测 API 是否存在('navigationPreload' in registration)远远不够。必须调用 enable() 并确保 Promise 完成,否则功能默认关闭:
- 在
navigator.serviceWorker.register()的then回调中执行registration.navigationPreload.enable() - 加上容错处理:
.catch(() => {}),避免不支持时抛错中断流程 - Safari
fetch 中安全使用 preloadResponse
event.preloadResponse 是一个可能失败的 Promise,不能直接返回或链式裸调用:
- 只对
event.request.destination === 'document'的请求启用,排除图片、脚本、API 等非导航请求 - 始终用
.then(r => r).catch(() => null)包裹,防止拒绝导致整个响应链中断 - 采用三级 fallback:优先用预加载响应 → 缓存匹配 → 最终 fetch,顺序不可颠倒
必须搭配预缓存才完整生效
Navigation Preload 解决“新请求不等 SW”,但无法替代静态资源的本地秒回:
- 在
install阶段用caches.open().addAll([...])预存首页骨架(/index.html、关键 CSS/JS),HTML 必须是构建时生成的纯静态版本 - 禁止在 install 中用
fetch()动态拉首页——存在权限限制、流消费问题和动态内容语义风险 - 最终 fetch 响应策略推荐:
preloadResponse.then(r => r || caches.match(...)).catch(() => caches.match(...)).then(r => r || fetch(...))
注意生命周期与 waitUntil
常见报错 “The service worker navigation preload request was cancelled before 'preloadResponse' settled” 表明 fetch 事件提前结束,导致预加载被取消:
- 必须用
event.waitUntil()包裹异步链,确保浏览器等待preloadResponse完成 - 例如:
event.respondWith(...); event.waitUntil(event.preloadResponse.catch(() => {})); - 该机制在 Chrome、Edge、Firefox 和 Safari 11.3+ 已稳定支持,冷启动或快速刷新时依然有效










