service worker 被强制终止是系统策略而非代码缺陷,需通过 visibilitychange/pagehide/freeze 事件感知状态、用 indexeddb 持久化待发消息、依赖 background sync 实现自动重连与补发,并由页面兜底校验与重注册。
service worker 被系统强制终止不是代码缺陷,而是 android/ios 对后台进程的统一管控策略——它本身不支持长期驻留,也没有“保活”能力。所谓“自愈”,本质是快速检测 + 可靠重启 + 状态续传,而非阻止被杀。
监听可见性与生命周期事件,及时响应状态变化
页面切后台时,Service Worker 很可能在几秒到几分钟内被系统回收(尤其 Android 低内存或 iOS 后台限制)。不能依赖它持续运行,但可以提前感知并准备恢复:
- 在主页面监听 visibilitychange:document.hidden 为 true 时,暂停定时同步、关闭未完成的 fetch 请求,但不调用 self.skipWaiting() 或 self.unregister()
- 监听 pagehide 和 freeze 事件(Chrome/Edge 支持),在页面冻结前将待发消息写入 IndexedDB 标记为 pending
- 避免在 SW 中使用 setInterval 或长时 setTimeout;改用 event-driven 模式(如 push、sync、message)触发逻辑
利用 sync 事件实现连接重建与消息补发
Service Worker 被杀后无法主动唤醒,但可通过浏览器提供的 background sync API 在网络恢复时自动触发重连和离线操作续传:
- 注册 sync 时使用带 tag 的命名(如 'reconnect' 或 'send-chat-123'),便于服务端幂等识别
- 在 sync 事件处理中:先检查当前网络状态(navigator.onLine),再尝试建立 WebSocket 连接;连接成功后再从 IndexedDB 读取 pending 消息批量重发
- 若 sync 失败(如网络仍不可用),浏览器会按指数退避策略自动重试(通常 5min → 10min → 20min),无需手动轮询
配合客户端页面做兜底校验与状态同步
Service Worker 不可靠,前端页面必须承担“最终仲裁者”角色:
- 页面恢复可见(visibilityState === 'visible')时,立即检查 navigator.serviceWorker.controller?.state 是否为 'activated'
- 若 controller 为 null 或 state !== 'activated',说明 SW 已失效,需调用 navigator.serviceWorker.register() 重新注册,并触发一次手动同步(如拉取未读摘要、重置心跳时间戳)
- 关键业务操作(如提交表单、确认支付)始终走页面直连 + 服务端幂等 key(如 requestId),不依赖 SW 中转,避免因 SW 丢失导致指令丢失或重复
生产环境必须关闭调试残留,防止开发污染
本地开发常因多个项目共用 localhost 导致 SW 缓存错乱,上线后也会因旧版本残留引发“总是显示旧界面”问题:
- 上线前确保 manifest.json 的 start_url 和 scope 与实际部署路径严格一致(如 /app/ 不能写成 /)
- 每次更新 SW 文件内容(哪怕只加一行注释),强制触发版本变更;避免仅修改缓存策略却不改文件哈希
- 在 production build 脚本中加入清理逻辑:注册新 SW 后,主动调用 oldWorker?.unregister(),并提示用户刷新(可选)










