Service Worker离线缓存的关键在于fetch事件中动态决定响应来源,依赖注册、install预缓存、fetch响应控制三环节闭环;需HTTPS环境注册,install阶段用caches.open和addAll预存资源并waitUntil,fetch中用respondWith匹配缓存或网络,activate阶段清理旧缓存并调用skipWaiting和clients.claim。

在 Service Worker 中用 fetch 事件拦截请求并实现离线缓存,关键不是“把资源存进去”,而是“在每次请求发生时,主动决定从缓存还是网络取内容”。它依赖三个核心环节闭环:注册成功、安装时预存关键资源、fetch 事件中即时响应。
必须先注册且运行在安全上下文
Service Worker 只能在 HTTPS 或 localhost 环境注册。主页面 JS 中写:
- 检查兼容性:
if ('serviceWorker' in navigator) - 在
window.addEventListener('load', ...)中调用navigator.serviceWorker.register('/sw.js') - 确保
sw.js放在根目录,或显式指定{ scope: '/' }才能控制全站
install 阶段预缓存静态资源
这是离线可用的前提。在 sw.js 的 install 事件里一次性存入确定不变的核心文件:
- 用
caches.open('static-v1')创建带版本号的缓存空间 -
cache.addAll(['/', '/index.html', '/app.css', '/logo.png'])—— 路径必须和页面实际请求 URL 完全一致(含尾斜杠、查询参数) - 整个操作必须包裹在
event.waitUntil()中,否则安装可能提前结束
fetch 事件中真正启用离线能力
浏览器发出每个请求时都会触发这个事件,你必须第一时间用 event.respondWith() 控制响应来源:
立即学习“Java免费学习笔记(深入)”;
- 开头就写
event.respondWith( async () => { ... } ),不能漏掉或放在条件分支外 - 对 HTML 页面(
request.destination === 'document')优先查缓存:const cached = await caches.match(event.request) - 命中则直接返回;未命中则
fetch(event.request)并可选地cache.put(request, response.clone())(注意clone(),Response 流只能读一次) - 过滤跨域请求:
new URL(req.url).origin !== location.origin的跳过拦截,避免误拦 CDN 或第三方接口
activate 阶段清理旧缓存并接管页面
每次更新缓存逻辑后,旧缓存不会自动消失,需手动清理并确保新 SW 生效:
- 在
activate事件中调用caches.keys()获取所有缓存名 - 筛选出非当前版本的缓存(如当前是
static-v2,就删掉static-v1) - 调用
caches.delete(key),同样用event.waitUntil()包裹异步操作 - 加上
self.skipWaiting()和self.clients.claim(),让新 SW 立即激活并接管已有页面


















