Service worker 注册与 scope
一句话: navigator.serviceWorker.register(scriptURL, { scope }) 注册一个 service worker,它会拦截路径以 scope 开头的所有 URL 的 fetch 事件。scope 默认为 worker 脚本所在目录,只能收窄、不能扩展到该范围之外——除非服务器返回 Service-Worker-Allowed 响应头。
注册如何工作
Section titled “注册如何工作”调用 register() 是幂等的——若相同脚本已在该 scope 注册,浏览器会忽略此次调用。无论是否触发了新的安装,返回的 Promise 都会 resolve 为一个 ServiceWorkerRegistration 对象。
if ('serviceWorker' in navigator) { navigator.serviceWorker .register('/sw.js', { scope: '/' }) .then((registration) => { console.log('注册成功。Scope:', registration.scope); }) .catch((err) => { console.error('注册失败:', err); });}注册应在页面主要内容加载完成后进行,而非放在 <head> 顶部,以免与关键资源抢占带宽。
Scope 控制什么
Section titled “Scope 控制什么”scope 是一个 URL 路径前缀。注册了 scope /app/ 的 service worker 会拦截:
/app//app/dashboard/app/settings/profile
但不会拦截:
/(根路径)/blog//app-launcher/(不同前缀)
scope 不限制 worker 通过 fetch() 发起请求的目标 URL,只限制哪些页面导航和子资源请求会被 提供给该 worker 处理。
默认 Scope
Section titled “默认 Scope”若未指定 scope 选项,默认为 worker 脚本所在目录:
- Worker 位于
/sw.js→ 默认 scope/ - Worker 位于
/app/sw.js→ 默认 scope/app/
将 worker 放在根路径(/sw.js)可获得最大默认 scope。
通过 Service-Worker-Allowed 扩展 Scope
Section titled “通过 Service-Worker-Allowed 扩展 Scope”/app/sw.js 通常无法声明 / 的 scope——其范围受自身路径约束。若需要更大的 scope,服务器必须在浏览器拉取 worker 脚本时附上 Service-Worker-Allowed 响应头:
Service-Worker-Allowed: /若没有此响应头,以 { scope: '/' } 注册 /app/sw.js 会抛出 DOMException。
同一来源可以有多个注册,允许为不同子应用部署不同的 worker:
// Worker A 覆盖营销页面navigator.serviceWorker.register('/sw-marketing.js', { scope: '/marketing/' });
// Worker B 覆盖应用外壳navigator.serviceWorker.register('/sw-app.js', { scope: '/app/' });Scope 之间可以重叠——浏览器在判断由哪个 worker 处理请求时,会匹配最具体(最长)的 scope。保持 scope 不重叠是运维层面的最佳实践,而非注册约束。
updateViaCache
Section titled “updateViaCache”默认情况下,浏览器在获取 worker 脚本时会遵循其 HTTP 缓存,若脚本被积极缓存可能延迟更新。设置 updateViaCache: 'none' 可让浏览器始终绕过 worker 脚本本身的 HTTP 缓存:
navigator.serviceWorker.register('/sw.js', { scope: '/', updateViaCache: 'none',});W3C Service Workers 规范将 updateViaCache 定义为控制 HTTP 缓存是否被用于 worker 脚本('all')、其导入脚本('imports',默认值)或二者均不使用('none')。
- 在
DOMContentLoaded或load事件后注册,避免与资源加载竞争。 - 将 worker 脚本放在所需 scope 路径层级尽可能高的位置(
/sw.js对应/,/app/sw.js对应/app/)。 - 注册时使用
updateViaCache: 'none',确保浏览器始终检查新版本。 - 在开发环境中打印
registration.scope,确认 worker 覆盖了预期路径。 - 多应用站点应定义不重叠的 scope,并为每个 scope 部署独立的 worker。
- Service Worker 生命周期 — 注册之后发生的事(install、activate、waiting)
- 更新流程与 skipWaiting — 新版本如何替换旧版本
- Manifest scope — Web App Manifest 中的类似概念