Service Worker 如何提升前端加载性能?缓存策略怎么选?
简化版
Service Worker 可以拦截同源请求,把静态资源或接口响应缓存到 Cache Storage,从而提升二次访问速度和弱网可用性。常见策略有 Cache First、Network First、Stale While Revalidate 和 Network Only。选择策略要看资源变化频率、实时性要求和离线需求,同时要处理版本更新、缓存清理、降级和安全边界。
详细版
Service Worker 位于页面和网络之间,能代理请求。它常用于 PWA、离线缓存和二次访问加速。
| 策略 | 含义 | 适合场景 |
|---|---|---|
| Cache First | 先读缓存,没缓存再请求网络 | 带 hash 的静态资源 |
| Network First | 先请求网络,失败再读缓存 | 需要较新数据的页面 |
| Stale While Revalidate | 先返回缓存,同时后台更新 | 可接受短暂旧数据的列表 |
| Network Only | 只走网络 | 支付、提交等敏感请求 |
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
return cached || fetch(event.request)
})
)
})
Service Worker 是性能工具,但不是安全边界;关键业务接口仍要由服务端保证权限、幂等和一致性。
完整版教学
一、Service Worker 为什么能提速
普通页面请求资源时要经过浏览器缓存和网络。Service Worker 额外提供了一层可编程代理,可以决定每个请求是走缓存、走网络,还是两者结合。
它对二次访问、弱网、离线场景特别有价值。用户再次打开页面时,核心静态资源可以直接从 Cache Storage 返回。
二、生命周期要理解
Service Worker 有 install、activate、fetch 等阶段。安装时可以预缓存关键资源,激活时可以清理旧版本缓存,fetch 时拦截请求。
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== 'app-v2').map(k => caches.delete(k)))
)
)
})
如果不清理旧缓存,用户磁盘空间会被慢慢占用,也可能继续拿到旧资源。
三、静态资源怎么缓存
带内容 hash 的 JS、CSS、图片适合 Cache First,因为文件名变了就代表内容变了。HTML 通常不建议长期 Cache First,因为它负责引用最新资源清单。
对于静态资源,更推荐构建产物 hash + 长缓存 + SW 清理旧版本。
四、接口数据怎么缓存
接口数据要看实时性。商品分类、配置、文章列表可以用 Stale While Revalidate;用户余额、订单状态、权限信息不适合直接缓存。
错误的接口缓存会造成业务不一致,这比慢一点更严重。
五、更新策略要设计清楚
Service Worker 更新不是用户刷新一次就一定完成。新 SW 下载后通常会等待旧页面关闭。
可以根据业务选择:
- 静默等待下次访问生效。
- 提示用户发现新版本并刷新。
- 在安全场景下使用
skipWaiting和clients.claim,但要避免新旧资源不兼容。
六、和 HTTP 缓存的关系
Service Worker 不替代 HTTP 缓存。更合理的是两者配合:
| 层级 | 作用 |
|---|---|
| HTTP 缓存 | 浏览器内建缓存协商 |
| CDN 缓存 | 边缘节点加速 |
| Service Worker | 应用可编程缓存和离线策略 |
实际请求可能同时经过多层缓存,因此要避免缓存规则互相打架。
七、常见误区与追问
- 误区:Service Worker 只要缓存越多越好。 缓存过多会占空间、增加更新复杂度,也可能返回旧数据。
- 误区:所有接口都适合离线缓存。 强实时和敏感接口不适合直接缓存。
- 误区:Service Worker 能解决所有首屏慢。 首次访问仍要下载和注册 SW,它更擅长二次访问和离线体验。
- 追问:HTML 应该 Cache First 吗? 多数站点不建议长期这样做,否则用户可能拿不到最新资源入口。
- 追问:为什么需要清理旧缓存? 防止磁盘膨胀和旧资源继续被命中。
- 追问:SW 更新为什么有延迟? 新版本通常等待旧页面关闭后才激活,避免运行时代码被突然替换。
八、加强记忆
Service Worker 缓存记成“可编程缓存层”。静态资源偏 Cache First,实时数据偏 Network First,允许旧数据的列表可用 Stale While Revalidate;更新、清理和业务一致性必须一起设计。