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

Service Worker 本身不是“魔法”,它带来的变革取决于你用它解决什么问题——离线能力、资源预缓存、后台同步、消息推送,这些功能都得自己写逻辑,不是注册一个脚本就自动生效。
Service Worker 能拦截并重写 fetch 请求
这是它最核心的能力:在页面发起 fetch 或 XMLHttpRequest 时,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 接口该不该缓存?缓存多久?失效后怎么通知页面重试?这些没法靠工具自动生成,得结合业务接口语义来判断。










