Service Worker 与离线缓存策略

1. 什么是 Service Worker?

Service Worker 是一条独立于浏览器主线程运行的后台 JavaScript 线程。作为一个前端控制的代理服务器,它可以拦截页面的网络请求(fetch 事件),并决定是从网络获取数据还是从本地 Cache 获取,从而实现应用的离线可用和体验。

2. 生命周期

理解其生命周期对于避免版本更新问题非常重要:

  1. Install(安装中) Service Worker 文件下载并解析后触发。通常在这里预缓存页面的静态资源。此时新 Worker 尚未控制页面。
  2. Waiting(等待中) 如果当前还有使用旧版本 Worker 的页面处于打开状态,新版本 Worker 会进入等待阶段,不会直接生效。可以通过调用 self.skipWaiting() 强制其跳过等待,立即激活。
  3. Activate(激活) 新 Worker 正式接管页面。这里的最佳实践是清理旧版本 Worker 留下的陈旧缓存数据。调用 clients.claim() 可以让它在首次注册时立即控制当前页面。

3. 常见缓存策略

在拦截 fetch 事件后,常用的缓存与网络分发策略如下:

(1) 缓存优先

优先从本地缓存读取,如果没有命中才发起网络请求并存入缓存。 适用场景:基本不怎么变动的静态资源(如带 Hash 的 JS/CSS 文件、字体、Logo)。

(2) 网络优先

优先向服务器发起请求,如果网络异常或请求超时,则降级使用本地缓存中的数据。 适用场景:对实时性要求较高的数据(如文章列表、用户信息)。

(3) 陈旧重新验证

有缓存时优先返回缓存,立刻让页面渲染;同时在后台静默发起网络请求更新缓存。这样下次访问时就能拿到最新的数据。 适用场景:更新频率较高但允许短暂展示旧数据的资源(如用户头像、次要的展示图片)。

4. 注意事项

  • Service Worker 无法直接访问 DOM。如果需要与页面交互,必须通过 postMessage 进行跨线程通信。
  • 出于安全考虑,Service Worker 只能在 HTTPS 协议下注册(除了 localhost 本地开发环境)。