ServiceWorker 通过注册脚本、install 预缓存、fetch 拦截与 cache API 实现完全可控的离线缓存;需同源注册、waitUntil 保证 install 完成、activate 清理旧缓存并 claim 控制权。

前端应用中通过 ServiceWorker 拦截并处理网络缓存,核心在于注册脚本、控制生命周期、监听 fetch 事件,并主动调用 Cache API 进行读写。它不依赖 HTTP 缓存头,而是由你完全掌控“什么资源缓存、何时返回、是否更新”。
注册与激活 ServiceWorker
必须在页面加载后注册,且脚本路径需在同源下(通常放根目录):
- 检查浏览器支持:
if ('serviceWorker' in navigator) - 在
window.addEventListener('load', ...)中调用navigator.serviceWorker.register('/sw.js') - 注册成功后,浏览器会触发 install 事件——这是预缓存静态资源的唯一可靠时机
在 install 阶段预置关键缓存
确保离线可用的第一步,是把 HTML、CSS、JS、图标等核心资源提前存入 Cache API:
- 使用
caches.open('v1-static')创建带版本号的缓存空间,避免升级冲突 - 调用
cache.addAll(['/index.html', '/app.js', '/style.css'])批量写入 - 务必在
event.waitUntil()内完成,否则 install 会失败
在 fetch 事件中执行缓存策略
这是拦截请求的核心环节。根据资源类型选择不同逻辑:
立即学习“前端免费学习笔记(深入)”;
- 静态资源(JS/CSS/字体/图片):优先查缓存,命中即返回,不走网络(“永不过期”策略)
- API 数据或 HTML 页面:可采用 stale-while-revalidate:先返回缓存内容,再后台拉新数据更新缓存
- 纯动态内容(如带时间戳的上报):跳过缓存,直连网络,避免陈旧数据干扰
示例代码片段(静态资源只读缓存):
self.addEventListener('fetch', event => {const url = new URL(event.request.url);
if (['.js', '.css', '.woff2', '.png'].some(ext => url.pathname.endsWith(ext))) {
event.respondWith(
caches.match(event.request).then(r => r || new Response('Not found', {status: 404}))
);
}
});
更新缓存与清理旧版本
ServiceWorker 升级不是覆盖,而是并行运行。需在 activate 阶段主动清理:
- 监听
activate事件,在其中调用caches.keys().then(keys => Promise.all(...)) - 只保留当前版本缓存(如
keys.filter(k => k !== 'v2-static')),其余全部 delete - 同时调用
clients.claim()让新 SW 立即接管已打开页面


















