PWA中Cache API缓存的资源怎么更新不生效?

小书妍 阅读 61

我在做PWA离线功能,用Cache API缓存了静态资源,但更新文件后刷新页面还是加载旧缓存,试过改cacheName也不行。

service worker里是这样写的:

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v2').then(cache => cache.addAll([
      '/',
      '/index.html',
      '/styles/main.css',
      '/scripts/app.js'
    ]))
  );
});

是不是哪里漏了?为什么新版本的文件刷不出来?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
一羽霏
一羽霏 Lv1
你这个问题很典型,核心原因是:改了cacheName后没有清理旧缓存,浏览器还是会从旧缓存里拿。

你的代码只写了install事件缓存资源,但没做两件事:

1. activate事件没清理旧缓存 - cacheName改成v2后,旧缓存还在角落里躺着呢
2. fetch事件没拦截请求 - 浏览器不知道要从缓存里取还是网络请求

简单修复:在service worker里加上activate事件清理旧缓存

self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(keys => {
return Promise.all(
keys.filter(key => key !== 'v2')
.map(key => caches.delete(key))
);
})
);
});

self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});


简单说下逻辑:activate里遍历所有缓存,把不是v2的旧缓存全删掉。fetch里优先查缓存,缓存没有才走网络。

另外提醒一下,每次改完service worker要让浏览器重新注册SW,浏览器才会更新。可以在registration对象上监听updatefound,或者直接开无痕模式测试,避免缓存干扰。

还有一种更省心的写法是用workbox,不过如果你就这几個文件,手写也没问题。
点赞
2026-03-14 10:03
Top丶玉鑫
问题是你的service worker只写了install缓存资源,但没写fetch事件去拦截请求返回缓存。浏览器请求时没走你的缓存,直接走了默认的网络。

加上fetch事件:

self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
return caches.open('v2').then(cache => {
cache.put(event.request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
});

self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(key => key !== 'v2').map(key => caches.delete(key)))
)
);
});


改完记得在浏览器里手动更新service worker,或者在代码里加skipWaiting强制更新。
点赞
2026-03-13 05:00