Service Worker从入门到精通我的实战踩坑经验分享
Service Worker搞不定离线缓存,我差点抓狂
前几天在项目里加了个Service Worker来搞离线缓存,结果发现页面加载不出来,缓存也没生效。折腾了半天发现原来是注册Service Worker的方式不对,还有一些细节没处理好。
先说解决方案,再聊聊为什么
最终的解决方法是这样的:
// 注册Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
});
}
这里我踩了个坑,一开始我把Service Worker的注册放在了DOMContentLoaded事件里,结果页面加载不出来。后来试了下发现,应该在window的load事件里注册,这样才能确保所有的资源都加载完毕。
缓存策略也得搞清楚
接下来是缓存策略的问题。我最初写的代码是这样的:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
);
});
这个策略看起来挺简单的,就是先从缓存里找,找不到就去网络上拉。但问题是这样会导致一些动态资源(比如API请求)也被缓存下来,导致数据不更新。后来改成了这样:
const CACHE_NAME = 'my-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request).then(networkResponse => {
if (networkResponse && networkResponse.ok) {
const cacheCopy = networkResponse.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, cacheCopy);
});
}
return networkResponse;
});
})
);
});
这样就能确保静态资源被缓存下来,而动态资源每次都去网络上拉取。这个方案虽然复杂一点,但效果更好。
还有一个小问题
解决了上面的问题后,又遇到了一个奇葩情况:有些页面加载出来的样式不对。查了半天发现是CSS文件的版本号没更新,浏览器还在用旧的缓存。最后在URL后面加了个版本号参数解决了这个问题:
const urlsToCache = [
'/',
'/index.html?v=1.0',
'/styles.css?v=1.0',
'/script.js?v=1.0'
];
虽然有点土,但确实有效。
总结一下
以上是我踩坑后的总结,希望能对你有帮助。如果你有更好的方案或者遇到过类似的问题,欢迎评论区交流。这个技巧的拓展用法还有很多,后续会继续分享这类博客。
本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
登录/注册
设计师丽君
Lv1
读完这篇文章,我对自己的知识体系有了新的认识,找到了需要补充的短板。
点赞
7
2026-01-30 23:25