如何修改Service Worker代码实现PWA的Network First then Cache策略
解决方案
现有代码的fetch逻辑为缓存优先、网络兜底,所以会始终优先读取本地已缓存的旧资源,不会主动拉取最新内容。修改后可实现网络优先的加载策略,完整可运行代码如下:
完整修改后代码
// 定义缓存版本号,更新资源时修改版本号即可触发缓存更新 const staticCacheName = "pwa-static-v1" const assets = [ "/", "/index.html", "/about.html", "/assets/css/main.css", "/images/logo.png", "/images/logo.svg", ] self.addEventListener("install", installEvent => { installEvent.waitUntil( caches.open(staticCacheName).then(cache => { cache.addAll(assets) }).then(() => { // 新Service Worker安装完成后立即生效,无需等待旧SW退出 self.skipWaiting() }) ) }) self.addEventListener("activate", activateEvent => { activateEvent.waitUntil( caches.keys().then(cacheNames => { // 清理所有旧版本缓存,避免冗余 return Promise.all( cacheNames.filter(name => name !== staticCacheName) .map(name => caches.delete(name)) ) }).then(() => { // 立即接管所有打开的页面 self.clients.claim() }) ) }) self.addEventListener("fetch", fetchEvent => { // 仅处理GET请求,非GET请求直接走网络 if (fetchEvent.request.method !== 'GET') { fetchEvent.respondWith(fetch(fetchEvent.request)) return } fetchEvent.respondWith( // 优先发起网络请求 fetch(fetchEvent.request) .then(networkRes => { // 仅缓存请求成功的响应,避免缓存4xx/5xx等错误内容 if (networkRes.ok) { caches.open(staticCacheName).then(cache => { // 响应为流只能使用一次,缓存需使用克隆后的副本 cache.put(fetchEvent.request, networkRes.clone()) }) } return networkRes }) .catch(() => { // 网络请求失败(离线/网络异常),返回已缓存的资源 return caches.match(fetchEvent.request) }) ) })
关键修改说明
- 补全了
staticCacheName缓存版本变量,后续发布新版本资源时只需修改版本号,即可自动清理用户本地旧缓存 - 新增
activate事件逻辑,自动清理旧版本缓存,避免冗余缓存冲突 install事件新增self.skipWaiting(),新Service Worker安装后立即生效,无需用户关闭旧页面再重新打开- 重写
fetch事件逻辑,实现预期的网络优先策略:- 优先发起网络请求拉取最新资源,请求成功后将最新资源更新到缓存,保证离线时的缓存始终是最新版本
- 网络请求失败时自动兜底返回已缓存的资源,保障离线可用性
- 仅对2xx状态的正常响应做缓存,避免缓存错误页面
内容的提问来源于stack exchange,提问作者user17578790
相关产品推荐
相关产品推荐

