AngularJS应用Service Worker资源缓存加载及版本更新问题
解决Service Worker重复加载资源与版本控制问题
嘿,我之前在做AngularJS项目的时候也碰到过一模一样的问题!咱们一步步拆解来解决它——既要让资源完全从Service Worker缓存加载,还要保证更新能及时生效。
首先得说清楚你现在遇到重复加载的原因:一是你用了非标准的useCache: true参数(浏览器根本不识别这个),二是没有编写正确的Fetch拦截逻辑让Service Worker接管资源请求。咱们一步步改:
第一步:修正Service Worker注册代码
先把无效的useCache: true删掉,而且最好等页面加载完成后再注册SW,避免干扰首次渲染:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('ServiceWorker 注册成功,作用域:', registration.scope); }) .catch(err => { console.log('ServiceWorker 注册失败:', err); }); }); }
第二步:编写Service Worker的Fetch拦截逻辑
这是核心!在service-worker.js里监听fetch事件,拦截静态资源请求,优先从缓存返回,没有缓存再去网络请求并缓存。同时加入版本控制逻辑:
// 缓存名称带版本号,更新资源时修改这个版本号即可 const CACHE_NAME = 'my-angular-app-v1'; // 列出需要预缓存的静态资源(根据你的项目实际文件调整) const ASSETS_TO_CACHE = [ '/', '/index.html', '/custom.css', '/app.js', // 其他JS/CSS/图片等静态资源... ]; // 安装阶段:预缓存初始资源 self.addEventListener('install', (event) => { // 等待缓存操作完成再结束安装 event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('打开缓存,开始预加载资源'); return cache.addAll(ASSETS_TO_CACHE); }) .then(() => self.skipWaiting()) // 强制激活新SW,不用等旧SW控制的页面关闭 ); }); // 激活阶段:删除旧版本缓存,避免冗余 self.addEventListener('activate', (event) => { const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { // 删除不在白名单里的旧缓存 if (!cacheWhitelist.includes(cacheName)) { console.log('删除旧缓存:', cacheName); return caches.delete(cacheName); } }) ); }).then(() => self.clients.claim()) // 立即控制所有打开的页面 ); }); // Fetch事件:拦截请求,优先返回缓存资源 self.addEventListener('fetch', (event) => { // 只拦截GET请求的静态资源(可根据需求调整规则) if (event.request.method === 'GET' && (event.request.url.includes('.js') || event.request.url.includes('.css') || event.request.url.includes('.html'))) { event.respondWith( caches.match(event.request) .then(response => { // 如果缓存中有资源,直接返回 if (response) { console.log('从缓存返回资源:', event.request.url); return response; } // 缓存中没有,去网络请求,然后存入缓存 return fetch(event.request) .then(networkResponse => { caches.open(CACHE_NAME) .then(cache => { cache.put(event.request, networkResponse.clone()); }); return networkResponse; }); }) ); } });
第三步:版本控制确保资源更新生效
要避免用户一直加载旧资源,推荐两种方式结合:
- 缓存版本号更新:当你修改了JS/CSS资源后,把
service-worker.js里的CACHE_NAME版本号改掉(比如从v1改成v2)。新SW安装时会创建新缓存,激活时自动删除旧缓存,用户下次访问就会加载新资源。 - 资源文件名加哈希:更可靠的方式是给静态资源文件名加上内容哈希(比如
custom.abc123.css),可以通过Gulp/Webpack等构建工具自动生成。资源内容变化时URL也会变,SW会自动缓存新资源,旧资源会被逐步清理,彻底避免缓存旧内容的问题。 - 主动提示用户更新:如果需要立即让用户获取新内容,可以在index.html里加入SW更新检测逻辑:
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(registration => { registration.addEventListener('updatefound', () => { const newWorker = registration.installing; newWorker.addEventListener('statechange', () => { if (newWorker.state === 'installed') { // 提示用户刷新页面获取新内容 if (confirm('发现新版本!是否刷新页面更新?')) { window.location.reload(); } } }); }); }); }
为什么之前会出现重复加载?
- 你用了非标准的
useCache: true参数,SW注册时没有正确配置,导致SW没有完全接管请求。 - 没有编写Fetch事件拦截逻辑,浏览器还是会直接发起网络请求,同时SW可能在后台缓存资源,所以出现了重复加载的情况。
内容的提问来源于stack exchange,提问作者Pinal
相关产品推荐
相关产品推荐

