You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:11:54