Service Worker缓存策略更新后页面还是加载旧资源怎么办?

书生シ洋洋 阅读 28

最近给项目加了Service Worker做静态资源缓存,但今天部署新版本后发现用户还是在加载旧资源。我尝试过清除浏览器缓存和用cache-first策略,但页面内容就是不更新,这是什么情况啊?

我设置的策略是先查缓存再请求网络,代码大概是这样写的:


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

后来试过在sw.js里加版本号,用caches.open('v1'),但用户升级到v2版本后旧缓存还是没清理掉。难道Service Worker本身没被重新注册吗?刷新页面的时候控制台也没有报错提示啊…

我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
W″春光
这个问题的关键在于Service Worker的更新机制和缓存清理策略。按照标准写法,Service Worker本身和它管理的缓存是两回事,你提到加了版本号但旧缓存没清理掉,这说明你在安装新版本时没有主动删除旧缓存。

先说一下正确的做法。你需要监听 installactivate 事件,在 activate 阶段清理旧缓存。下面是一个完整的代码示例:

const CACHE_NAME = 'v2';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js'
];

// 安装阶段缓存静态资源
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS_TO_CACHE))
.then(() => self.skipWaiting()) // 立即接管页面
);
});

// 激活阶段清理旧缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if (cache !== CACHE_NAME) {
return caches.delete(cache); // 删除非当前版本的缓存
}
})
);
}).then(() => self.clients.claim()) // 确保新Service Worker立即生效
);
});

// 请求拦截逻辑
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then(cacheRes => {
return cacheRes || fetch(event.request);
})
);
});


有几个点需要注意。首先,Service Worker文件本身必须发生变化才能触发更新,所以你加版本号是对的,但记得确保文件内容确实有改动,比如修改注释或者变量名。其次,activate 阶段是清理旧缓存的最佳时机,而不是在 install 阶段做这件事,因为这时旧的Service Worker可能还在运行。

最后吐槽一句,调试Service Worker真的挺烦的,尤其是缓存问题,建议在开发阶段把Chrome DevTools的“Update on reload”选项打开,这样每次刷新都会强制更新Service Worker,省得抓狂。

如果还是有问题,检查一下是不是浏览器对Service Worker文件也做了强缓存,比如你的服务器配置了过长的 Cache-Control 头,这种情况下需要调整服务器响应头,确保 sw.js 文件不会被缓存太久。
点赞 1
2026-02-16 20:01
建宇 Dev
你遇到的问题是典型的 Service Worker 缓存未更新问题,其实本质上是旧缓存没有被清除导致的。你目前的策略是 cache-first,这种策略确实会优先使用缓存内容,哪怕缓存中的是旧版本资源。

### 问题核心

你已经尝试在 caches.open('v1') 中使用版本号来控制缓存,但如果你没有在 Service Worker 更新时主动删除旧缓存,浏览器不会自动清理它们。也就是说,v1 的缓存会一直存在,直到你手动清除或更新 SW 时没有处理旧缓存。

### 解决方法

你需要做两件事:

1. **强制 Service Worker 更新**
2. **在激活阶段清除旧缓存**

### 示例代码

修改你的 sw.js 文件,添加 installactivate 阶段处理逻辑:

const CACHE_NAME = 'v2'; // 更新版本号

self.addEventListener('install', (event) => {
// 安装阶段跳过等待,直接激活新 SW
self.skipWaiting();
});

self.addEventListener('activate', (event) => {
// 清除旧版本缓存
event.waitUntil(
caches.keys().then((keys) => {
return Promise.all(
keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))
);
})
);
});

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


### 额外说明

- 确保你的 Service Worker 文件(sw.js)有更新内容,否则浏览器不会重新注册 SW。
- 建议每次部署新版本时都更新 CACHE_NAME
- 页面刷新不一定触发 SW 更新,只有当浏览器认为 SW 文件内容发生变化时才会触发。可以考虑在注册 SW 时加上时间戳避免缓存:navigator.serviceWorker.register('/sw.js?_=时间戳')

这样改完之后,下次更新时应该不会再出现加载旧资源的问题了。
点赞 8
2026-02-03 22:08