Service Worker注册后不会立即生效,需等待激活;fetch事件不触发因新SW处于installed状态,仅新页面或调用clients.claim()才受控;activate事件是清理旧缓存唯一安全时机,须用event.waitUntil()包裹。

Service Worker 不会自动接管已打开的页面,也不在注册后立刻生效——这是绝大多数人踩坑的第一步。
注册后为什么 fetch 事件没触发?
注册只是把脚本下载并解析,后续状态推进完全异步,且受页面生命周期制约。常见现象是:注册成功、控制台看到 install 日志,但刷新页面后仍走网络请求,fetch 事件压根不执行。
- 根本原因:新注册的 Service Worker 处于
installed状态(即“等待激活”),它不会拦截当前已加载页面的请求 - 只有新打开的页面(或调用
clients.claim())才可能被立即控制 - 如果已有旧版 SW 正在运行,新版必须等所有客户端关闭旧版后才能激活,除非显式调用
skipWaiting() - HTTPS 是硬性前提;本地开发可用
localhost,但http://127.0.0.1在部分浏览器中也会失败
如何可靠触发 activate 并清理旧缓存?
activate 事件只在 Service Worker 进入 activated 状态时触发一次,它是清理旧缓存、迁移数据的唯一安全时机——因为此时旧 SW 已完全退出,不会出现缓存竞争。
- 务必在
activate中使用event.waitUntil()包裹清理逻辑,否则可能被中断 - 不要在
install阶段清理旧缓存:此时新旧 SW 可能共存,删错缓存会导致页面白屏 - 典型清理模式:
caches.keys().then(keys => Promise.all(keys.map(key => key.startsWith('my-cache-') && key !== 'my-cache-v2' ? caches.delete(key) : null))) - 避免直接用
caches.delete('old-cache')硬编码名称,应结合版本前缀做匹配
statechange 监听不到 parsed 或 installing?
statechange 事件只能监听到从 installed 开始的状态变更,parsed 和 installing 不会触发该事件——它们发生在注册 Promise 的 resolve 之后、事件监听器挂载之前。
立即学习“前端免费学习笔记(深入)”;
- 想确认是否进入
installing,只能靠install事件回调里的console.log或断点 -
registration.installing、registration.waiting、registration.active是三个可读属性,分别对应当前处于各状态的 worker 实例,可用于判断进度 - 例如:注册后立即检查
if (registration.waiting) { registration.waiting.postMessage({type: 'SKIP_WAITING'}); },配合self.addEventListener('message', ...)响应 - 注意:
statechange是绑定在ServiceWorker实例上的,不是registration对象
真正难处理的不是状态流转本身,而是多个 tab 共存时的竞态——比如用户一边开着旧版页面,一边新开 tab 加载新版,两个版本的缓存策略可能冲突。这时候 skipWaiting() 和 clients.claim() 的调用时机、是否加 guard 条件,就决定了用户会不会突然看到资源加载失败或界面错乱。



















