Skip to content

Service Worker

Service Worker 是一种运行在浏览器后台的脚本机制,可以拦截网络请求、管理缓存,并支持离线能力、后台更新等场景。

它不是普通页面脚本,也不直接操作 DOM,而更像一个位于页面与网络之间的可编程代理。

它能做什么

  • 拦截请求
  • 缓存静态资源
  • 提供离线访问
  • 做资源预缓存
  • 配合推送、后台同步等能力

和 Web Worker 的区别

Service WorkerWeb Worker 都是独立线程能力,但职责不同:

  • Web Worker:更偏计算和并行处理
  • Service Worker:更偏网络代理、缓存与离线能力

基本注册

页面中注册:

js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then((registration) => {
    console.log('Service Worker 注册成功', registration)
  })
}

生命周期

install

通常用于预缓存静态资源。

activate

通常用于清理旧缓存、接管页面。

fetch

用于拦截页面发出的网络请求。

一个最小示例

js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('app-cache-v1').then((cache) => {
      return cache.addAll(['/', '/index.html', '/app.js', '/style.css'])
    }),
  )
})

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cachedResponse) => {
      return cachedResponse || fetch(event.request)
    }),
  )
})

常见缓存策略

Cache First

先查缓存,没有再走网络。

适合:

  • 静态资源
  • 版本化资源

Network First

优先走网络,失败后退回缓存。

适合:

  • 数据更新频率较高的页面
  • 在线优先场景

Stale While Revalidate

先返回缓存,再在后台更新缓存。

适合:

  • 内容允许短暂过期
  • 希望响应更快的场景

为什么它常和离线能力一起出现

因为 Service Worker 能拦截请求并返回缓存结果,所以即便断网,也可以为页面提供一定程度的可用性。

但要注意:

  • 离线可用不等于所有接口都可用
  • 真正离线应用通常还需要本地存储、同步策略和冲突处理

常见限制

  • 只能在 HTTPS 环境下使用(本地开发的 localhost 是例外)
  • 不能直接访问 DOM
  • 生命周期独立于页面,调试和更新比普通脚本更复杂

更新问题

Service Worker 更新不是简单刷新页面就立即替换,常见现象包括:

  • 新版本已安装,但旧版本仍在控制页面
  • 必须关闭旧标签页后新版本才完全生效

因此实际项目中通常要设计更新提示与激活策略。

和 HTTP 缓存的关系

Service Worker 不是 HTTP 缓存的替代品,而是更高一层的可编程缓存控制能力。

可以这样理解:

  • HTTP 缓存:浏览器内建规则
  • Service Worker:开发者可编程代理

两者经常一起使用。

使用建议

  • 如果只是普通静态资源加速,先用好 HTTP 缓存。
  • 只有在确实需要离线能力、资源代理、预缓存时,再引入 Service Worker
  • 上线后要重视版本更新策略,否则容易出现“用户一直拿旧资源”的问题。

基于 MIT 许可发布