主题
Service Worker
Service Worker 是一种运行在浏览器后台的脚本机制,可以拦截网络请求、管理缓存,并支持离线能力、后台更新等场景。
它不是普通页面脚本,也不直接操作 DOM,而更像一个位于页面与网络之间的可编程代理。
它能做什么
- 拦截请求
- 缓存静态资源
- 提供离线访问
- 做资源预缓存
- 配合推送、后台同步等能力
和 Web Worker 的区别
Service Worker 和 Web 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。 - 上线后要重视版本更新策略,否则容易出现“用户一直拿旧资源”的问题。
