Service Worker能为网页应用带来什么变革【教程】

Service Worker的核心能力是拦截并重写fetch请求,需显式监听且仅对HTTPS生效;其缓存策略、生命周期管理及业务语义适配需手动设计,无开箱即用的“银弹”。

Service Worker 本身不是“魔法”,它带来的变革取决于你用它解决什么问题——离线能力、资源预缓存、后台同步、消息推送,这些功能都得自己写逻辑,不是注册一个脚本就自动生效。

Service Worker 能拦截并重写 fetch 请求

这是它最核心的能力:在页面发起 fetchXMLHttpRequest 时,SW 可以捕获请求、返回缓存、转发到网络、甚至合成响应。但要注意:

  • 只对 HTTPS 页面生效(localhost 是例外)
  • 必须用 self.addEventListener('fetch', ...)

    显式监听,不写就不会拦截
  • 默认不处理 iframe 等导航类请求,除非显式匹配 request.destination === 'document'
  • 缓存策略要自己决定:是优先缓存(cache-first)、优先网络(network-first),还是 stale-while-revalidate?没有银弹

Cache API 不等于 localStorage,用错就白忙活

cache.put()cache.match() 操作的是 Cache 对象,和 localStorage 完全无关。常见误区:

  • cache.keys() 返回的是 Request 对象,不是字符串 URL,不能直接 console.log 出可读地址
  • 缓存键是完整 URL + method + headers,https://a.com/https://a.com/?t=1 是两个不同缓存项
  • 没调用 cache.delete()cache.addAll() 就更新 SW 版本,旧缓存会一直留着,新 SW 拿不到
  • cache.addAll() 遇到任一资源失败就会整体回滚,不适合混入不确定可用的第三方 URL

install / activate / fetch 三阶段生命周期容易误判状态

SW 不是“启动即运行”,它有明确的状态流转:

  • install 阶段里如果 event.waitUntil() 中的 Promise 拒绝,安装失败,SW 不会进入 waiting 状态
  • 新 SW 默认处于 waiting 状态,直到所有旧页面关闭或手动调用 skipWaiting(),否则不会 activate
  • activate 阶段适合清理旧缓存(用 cache.keys().then(keys => keys.forEach(...))),但此时 fetch 还没接管,别在这儿做网络请求
  • 页面刷新 ≠ 新 SW 立即生效;硬刷新(Ctrl+F5)会绕过磁盘缓存,但不强制跳过 SW,真正生效要看 activate 是否完成

真正难的不是注册 SW,而是设计缓存粒度、降级路径和版本迁移逻辑——比如一个 JSON 接口该不该缓存?缓存多久?失效后怎么通知页面重试?这些没法靠工具自动生成,得结合业务接口语义来判断。