跳转到内容

Service worker 生命周期:install、activate 与更新

一句话: service worker 在控制页面之前会经历 注册 → 安装 →(等待)→ 激活。新版本 会在后台安装,但会停在 waiting 状态,直到使用旧版本的所有标签页关闭——因此更新是 原子的、绝不会半途生效,除非你主动调用 skipWaiting()clients.claim()

  • 原子更新。 页面的 HTML、JS 与缓存它们的 service worker 是一起版本化的。通过让 新 worker 停在 waiting 直到旧客户端全部消失,浏览器避免了标签页用新代码搭配旧 缓存(或反之)。
  • 离线安全。 worker 只有在 activate 成功后才接管,因此失败的安装永远不会替换掉 可用的离线副本。在新 worker 完全就绪前,旧 worker 持续提供服务。
  • 不会突然接管。 刚安装的 worker 默认不会控制已打开的标签页。现有页面保留当前 worker,使整个会话期间行为保持稳定。
  • 注册(Register)。 navigator.serviceWorker.register(url, { scope }) 让页面指向 一个 worker 脚本。注册是幂等的,并绑定到一个 scope。
  • 安装(Install)。 install 事件每个 worker 版本只触发一次——是用 event.waitUntil(...) 预缓存应用外壳的时机。安装失败会丢弃该 worker。
  • 等待(Waiting)。 若已有处于活动状态的 worker 正在控制客户端,新(已安装的) worker 会进入 waiting。在被旧 worker 控制的所有标签页关闭前,它不会激活。这就是 经典的“关掉每个标签页之前更新一直卡住”的现象。
  • 激活(Activate)。 worker 接管时触发 activate 事件——是清理旧缓存的时机。在 激活前,worker 不处理 fetch
  • 空闲 / 终止。 事件之间,浏览器可能停止 worker 以节省内存,并在下次事件时重启。 绝不要依赖跨事件的内存状态。
Browser / PlatformSupportSinceConfidenceSourceNotes
Chrome (Android)✅ yes40highref
Chrome (Desktop)✅ yes40highref
Edge (Desktop)✅ yes17highref
Safari (iOS)✅ yes11.3highrefStorage may be evicted after prolonged non-use.
Safari (macOS)✅ yes11.1highref
Firefox (Desktop)✅ yes44highref
Samsung Internet✅ yes4.0highref

Source: spec · MDN · Last verified 2026-06-24 · Confidence: high

目标 机制 含义
仅在所有标签页关闭后才应用更新(最安全) 什么都不做——默认等待行为。 用户在下次完全重启应用时拿到新版本;不会发生会话中途的切换。
立即激活新 worker install 中调用 self.skipWaiting() 跳过 waiting;需谨慎搭配,确保新 worker 的缓存与已加载页面匹配。
接管已存在但未受控的标签页 activate 中调用 self.clients.claim() 注册后的首次加载无需刷新即可受控。
强制检查更新 registration.update(),或普通刷新。 浏览器重新拉取 worker 脚本;字节不同的脚本会安装为新版本。
新 worker 上线时刷新所有标签页 监听 controllerchange,然后 location.reload() 避免 skipWaiting() + claim() 后出现新 worker 配旧页面的错配。
  • install 中用 event.waitUntil(...) 预缓存应用外壳。
  • activate 中用 event.waitUntil(...) 删除过期缓存。
  • 决定更新策略:默认等待(安全)还是 skipWaiting()(立即)。
  • 若使用 skipWaiting(),同时处理 controllerchange 以避免版本混用。
  • 仅在需要首次加载即受控且不刷新时,才使用 clients.claim()
  • 对不想发布的部署,保持 worker 脚本字节稳定——任何字节变更都会触发新安装。
  • 将 worker 视为无状态;任何需持久化的数据存入 Cache Storage 或 IndexedDB。

生命周期正是让 PWA 像原生应用一样可靠的原因:更新要么干净落地、要么完全不生效,离线 体验也绝不会在更新途中损坏。理解 waiting 能解释最常见的困惑——“我已经部署了,但用户 仍看到旧版本”——并让你在“安全的渐进上线”与“立即上线”之间做出有意识的选择。