更新策略
发布于
目标: 让新版本 service worker 触达用户的方式是一个经过权衡的选择,而不是意外落地的
默认行为。具体机制(skipWaiting()、clients.claim()、waiting 状态)见
更新流程参考;本指南讨论的是该在
这几种策略中如何取舍。
默认行为:一致性
Section titled “默认行为:一致性”如果不调用 skipWaiting(),新安装的 worker 会停留在 waiting 状态,直到所有由旧 worker
控制的标签页都关闭。默认行为偏向一致性:一个没有 service worker 的页面不会在会话中途
突然被接管;一个在某个 worker 版本下加载的页面,也不会被交给缓存假设不同的另一个版本。
对大多数应用而言,这种安静的默认行为就是正确的选择——但仅仅刷新并不能保证更新生效:
刷新期间,即使只有一个标签页,新旧页面的 client 也可能短暂重叠,因此只有当所有由旧
worker 控制的标签页都真正关闭或已导航离开时,等待中的 worker 才会接管。
用 skipWaiting() 立即接管
Section titled “用 skipWaiting() 立即接管”在 install 事件中调用 self.skipWaiting(),会让新 worker 在进入 waiting 阶段后立即
踢掉当前活动的 worker 并自行激活,即便它仍在控制着已打开的标签页。直接在 install
处理函数中调用是常见做法:
self.addEventListener('install', (event) => { self.skipWaiting();});代价是:这样一来,你的新 service worker 很可能正在控制着用旧版本加载的页面——如果新
worker 缓存的资源与页面上已有的 HTML 不兼容,就可能出问题。指导原则很直接——如果这可能
带来破坏,就不要无条件使用 skipWaiting()。
clients.claim() 是一个相关但独立的决定:它让新激活的 worker 接管那些在其注册时就已经
打开的页面。它只在首次加载时才真正有意义,因为得益于渐进增强,页面在没有 service worker
时通常也能正常工作——所以应把它当作按情况使用的选项,而非常规样板代码。
用户确认后再刷新
Section titled “用户确认后再刷新”一种折中方案是把 skipWaiting() 推迟到由用户驱动的时刻,而不是在 install 中无条件
调用:新 worker 安装并等待,页面向用户展示“有可用更新”的提示,只有在用户操作之后,页面
才会通过 postMessage() 通知等待中的 worker 触发 skipWaiting(),随后进行一次可控的
刷新。
// 在页面中:监听 controller 变化,并在用户同意更新之后只刷新一次。let refreshing = false;navigator.serviceWorker.addEventListener('controllerchange', () => { if (refreshing) return; refreshing = true; window.location.reload();});这种模式——完整说明见更新流程参考——
既避免了无条件 skipWaiting() 带来的隐性不一致风险,也避免了纯默认行为「更新要等所有
标签页关闭才生效」的代价。
周期性更新检查
Section titled “周期性更新检查”浏览器会在导航到域内页面时自动检查是否有新的 worker 脚本,也会在诸如 push 与 sync
之类的功能性事件发生时检查(除非此前 24 小时内已经检查过)。如果预计用户会长时间保持
某个标签页打开、既不导航也不刷新,你可能需要按一定间隔(例如每小时)主动调用
registration.update(),让长时间存活的会话也能在合理时间内发现新版本:
navigator.serviceWorker.register('/sw.js').then((reg) => { setInterval(() => reg.update(), 60 * 60 * 1000);});如何选择策略
Section titled “如何选择策略”| 场景 | 建议策略 |
|---|---|
| 常规应用;用户最终会关闭或导航离开所有标签页 | 默认行为(不调用 skipWaiting())——最简单、最一致。 |
| 用户会长时间保持标签页打开(数小时/数天) | 默认行为 + 周期性 registration.update() 检查,即使没有新的导航也能发现更新。 |
| 更新带有破坏性的缓存/schema 变化 | 默认行为,或用户确认后再刷新——绝不无条件使用 skipWaiting(),因为它可能接管带有不兼容假设的旧页面。 |
| 非破坏性修复,希望尽快生效,且可以接受一定干扰 | 在 install 中无条件调用 skipWaiting()。 |
- Service worker 更新流程与 skipWaiting —— 本指南在其间取舍的底层机制。
- 离线策略 —— 缓存策略与更新策略在感知新鲜度上有所重叠。
- Service worker 生命周期 —— 完整的 install/activate/waiting 流程。
← 返回指南总览。