Service Worker 缓存策略怎么选才不会导致页面更新延迟?

设计师梓童 阅读 2

我最近在项目里加了 Service Worker 做离线缓存,用了 cache-first 策略,结果发现用户每次发新版本后都看不到最新内容,得手动清除缓存才行。这体验太差了。

我试过改成 network-first,但首屏加载又变慢了,尤其弱网下特别明显。网上说可以组合策略,比如对 HTML 用 network-first,静态资源用 cache-first,但具体怎么写没搞明白。

这是我现在注册 SW 的代码:

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

有没有更合理的缓存策略推荐?或者怎么优雅地处理 HTML 和 JS/CSS 的不同缓存逻辑?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
设计师瑞丽
我来帮你一步步解决这个问题。其实你现在的思路是对的,关键是要对不同类型的资源采取不同的缓存策略。

第一步是修改你的 Service Worker 注册代码,让它能够区分 HTML 和静态资源。我们可以通过请求 URL 来判断:

self.addEventListener('fetch', event => {
// 这里判断是否是 HTML 页面
const requestUrl = new URL(event.request.url);
if (requestUrl.pathname.endsWith('/') ||
requestUrl.pathname.endsWith('.html')) {
handleHtmlRequest(event);
} else {
handleStaticRequest(event);
}
});

function handleHtmlRequest(event) {
event.respondWith(
fetch(event.request).then(response => {
// 对 HTML 页面总是从网络获取最新内容
return caches.open('pages-cache').then(cache => {
cache.put(event.request, response.clone());
return response;
});
}).catch(() => {
// 如果网络失败,尝试从缓存加载
return caches.match(event.request);
})
);
}

function handleStaticRequest(event) {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) {
// 对于静态资源先返回缓存内容
return cachedResponse;
}
return fetch(event.request).then(response => {
// 同时更新缓存
return caches.open('static-cache').then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
}


这段代码做了几件事:
- 对于 HTML 页面(通过路径判断),使用 network-first 策略,确保用户始终看到最新内容
- 对于其他静态资源(JS、CSS等),采用 cache-first 策略,提升首次加载性能

第二步是你需要定期清理过期的缓存。可以在 activate 事件中添加版本控制:

self.addEventListener('activate', event => {
const cacheWhitelist = ['pages-cache-v2', 'static-cache-v2'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});


这样每次部署新版本时,只要更新缓存名称就能自动清理旧缓存了。说实话这个方法虽然有点笨,但确实有效,至少比手动清缓存强多了。

记得在上线前测试一下弱网环境下的表现,毕竟用户体验才是最重要的。希望这些建议对你有帮助!
点赞
2026-03-31 01:05