无需登录 数据私有 本地保存

Service Worker 更新流程模拟器 - 等待/激活/刷新

28
0
0
0
/index.html
/about.html
/contact.html
/index.html
受控 SW: v1 (旧)
由旧 SW 控制
旧 Service Worker
已激活

版本: v1

控制页面: 3 个 (index, about, contact)

新 Service Worker
未安装

版本: v2 (待安装)

控制页面: 0 个

更新流程阶段
1 2 3 4 5
1.初始状态 → 2.检测更新 → 3.安装等待 → 4.激活 → 5.接管完成
操作面板
点击「检测更新」开始模拟 SW 更新流程。
事件日志
00:00🚀 模拟器已就绪。旧 SW v1 已激活,控制 3 个页面。
Service Worker 更新常见问题

这是 Service Worker 的核心设计机制。当浏览器检测到新的 SW 脚本并完成安装后,如果旧的 SW 仍在控制任何打开的页面,新 SW 就会进入 waiting 状态。这样可以防止同一应用同时运行两个不同版本的 SW,避免缓存不一致、请求拦截冲突等问题。新 SW 会一直等待,直到所有被旧 SW 控制的页面都关闭,或者开发者主动调用 skipWaiting() 方法。

skipWaiting() 会让等待中的新 SW 立即激活,即使旧 SW 仍在控制页面。风险在于:两个版本的 SW 可能同时处理请求(旧页面用旧 SW,新页面用新 SW),导致缓存版本冲突。通常推荐在以下场景使用:
① 配合 clients.claim() 一起使用,确保所有页面立即由新 SW 控制;
② 在 SW 的 install 事件中预缓存关键资源时;
③ 通过用户提示(如"新版本可用,点击刷新")引导用户操作时。

clients.claim() 让新激活的 SW 立即接管所有在它 scope 范围内的已打开页面(clients)。如果不调用此方法,新 SW 只会在后续新打开的页面或刷新后的页面中生效。默认情况下,SW 激活后不会自动接管已打开的页面,这是一种安全设计。调用 claim() 可以实现无缝切换,但需注意页面可能已经在旧 SW 的缓存策略下加载了部分资源。

可以通过监听 navigator.serviceWorker.registrationupdatefound 事件来检测更新。当新的 SW 开始下载时,该事件触发。然后监听新 SW 的 statechange 事件,当状态变为 installed(即 waiting)时,说明有更新等待激活。示例代码:
registration.addEventListener('updatefound', () => { const newSW = registration.installing; newSW.addEventListener('statechange', () => { if (newSW.state === 'installed' && navigator.serviceWorker.controller) { /* 有更新可用 */ } }); });

SW 生命周期分为 6 个阶段:
① Parsed(解析):浏览器解析 SW 脚本;
② Installing(安装中):触发 install 事件,通常用于预缓存资源;
③ Installed/Waiting(已安装/等待):安装成功,等待旧 SW 释放控制权;
④ Activating(激活中):触发 activate 事件,可清理旧缓存;
⑤ Activated(已激活):SW 已激活,可控制页面;
⑥ Redundant(冗余):SW 被替换或安装失败,不再使用。

推荐策略:
提示用户刷新:检测到更新后,在页面上显示提示条(如"新版本可用"),让用户主动点击刷新,这是最安全的做法;
自动 skipWaiting + claim:适合对一致性要求不高的应用,可实现完全无缝的更新,但需确保新 SW 能兼容旧页面的请求;
延迟激活:等待用户自然关闭所有页面后自动更新,适合后台工具类应用;
④ 使用 Registration.waiting.postMessage() 与 waiting 的 SW 通信,实现更精细的更新控制。