Service Worker 更新需主动协同以避免新旧混跑,关键在于检测更新、通知所有标签页、协调统一升级时机,并处理激活前的数据兼容性。

Service Worker 更新本身不自动同步到所有已打开的标签页,必须靠主动协同才能避免“新旧混跑”——比如一个标签页用着旧缓存,另一个加载了新逻辑,导致接口行为不一致、UI 错乱或离线失效。关键不是等浏览器自动切换,而是让所有页面感知更新、协商升级时机,并平滑过渡。
更新检测与通知所有标签页
当 Service Worker 安装成功(install)并等待激活(waiting)时,它已就绪但尚未接管页面。此时需主动通知所有同源标签页:
- 在新 Service Worker 脚本中,调用 self.clients.matchAll() 获取当前所有受控客户端列表
- 遍历每个 client,用 client.postMessage({ type: 'SW_UPDATE_READY' }) 发送升级提示
- 各页面监听 navigator.serviceWorker.addEventListener('message'),收到后可弹出轻量提示(如顶部横幅),不强制刷新
统一升级时机:避免多页各自 reload
多个标签页同时调用 skipWaiting() + reload() 会造成页面雪崩式刷新,影响用户操作。推荐采用“主控页协调”模式:
开发者平台元数据——GitHub、Docker Hub、crates.io 等生态系统注册表。使用此技能的时机:1. 解析 GitHub 仓库或获取其...
- 首个收到提示的页面(可通过 localStorage 时间戳或 BroadcastChannel 竞选)标记自己为“升级协调者”
- 协调者调用 registration.waiting?.postMessage({type: 'SKIP_WAITING'}) 触发激活
- 再通过 BroadcastChannel 广播 {type: 'SW_ACTIVATED'},其余页面监听到后才执行 location.reload()
- 这样保证只有一轮刷新,且所有页面在新 SW 激活后再同步重载
激活前的数据兼容性处理
新旧 Service Worker 可能使用不同缓存策略或 Cache 名称,直接切换会导致资源 404 或离线失败:
立即学习“前端免费学习笔记(深入)”;
- 新版 SW 在 install 阶段预建新 cache(如 v2-static),但不立即删除旧 cache(如 v1-static)
- activate 阶段再清理旧 cache:event.waitUntil(caches.delete('v1-static'))
- fetch 事件中做兜底:若新 cache 未命中,尝试 fallback 到旧 cache,确保过渡期资源可用
用户无感的静默升级(进阶)
对后台管理类应用,可跳过提示,完全静默完成升级:
- 页面首次加载时检查 navigator.serviceWorker.controller 是否为最新版本
- 若不是,在页面空闲时(如用户离开焦点 5 秒后)调用 registration.update()
- 新 SW 安装后,监听 controllerchange 事件,仅重新初始化关键模块(如权限校验、菜单树),不整页刷新
- 适合对稳定性要求高、且 UI 逻辑与 SW 解耦良好的系统


















