Service Worker 需HTTPS/localhost环境、页面重载后才生效,且SW文件须同源并可缓存;通过install预缓存、fetch拦截实现离线访问;fetch响应需clone才能复用;更新依赖skipWaiting与clients.claim。
Service Worker 是浏览器后台运行的脚本,它能拦截网络请求、缓存资源、实现离线访问——但它不是全局可用的,必须满足 HTTPS(或 localhost)环境,且注册后不会自动接管页面。
navigator.serviceWorker.register() 就生效?注册只是告诉浏览器“有这么个文件”,真正生效需要两个条件同时满足:
https:// 或 http://localhost 加载(file:// 协议完全不支持)Cache-Control: no-store 等禁止缓存的指令(否则浏览器可能反复拉取新版本失败)cache.addAll() 和 fetch 事件实现基础离线能力?核心逻辑是:安装阶段预缓存关键资源;运行时对匹配 URL 的请求优先返回缓存,未命中再走网络。注意 cache.addAll( 只接受相对路径(相对于 SW 文件位置),且会因任一资源失败而整体拒绝 Promise。
)
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache =>
cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js'
])
)
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
fetch() 返回的 Response 不能直接 put() 到 Cache?因为 fetch() 返回的 Response 流体(ReadableStream)只能读取一次。若想既返回给页面又存入缓存,必须用 response.clone() 分出副本:
cache.put(req, res) → 第二次读取时报错 TypeError: Failed to execute 'put' on 'Cache': Request body is already used
cache.put(req, res.clone()),然后用原 res 响应页面res.ok,避免把 404/500 错误页也缓存进去用户刷新页面时,浏览器可能还在用旧版 Service Worker,即使你已部署新 SW 文件。它只会在下次导航时静默下载并进入 waiting 状态——除非你主动调用 skipWaiting(),或让用户点击“刷新”触发 clients.claim()。这些细节不处理,离线功能看似正常,实则长期无法更新缓存内容。