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

Service Worker删除缓存后存储占用未下降问题排查与解决

问题分析与解决方案

原因分析

两种缓存删除场景的核心差异在于Service Worker的生命周期状态:

  1. 版本更新+skipWaiting时,旧Service Worker会被终止,新SW激活。此时旧缓存的所有引用被彻底释放,浏览器会立即回收对应的存储空间,所以Usage Storage正常下降。
  2. 消息指令删除缓存时,当前Service Worker仍处于活跃状态,即使调用caches.delete()从Cache Storage中移除了缓存条目,SW可能还持有缓存的内部引用(比如之前caches.open()创建的缓存实例),浏览器无法立即回收这些空间。后续fetch事件触发时,SW会重新创建同名缓存并写入新内容,导致存储持续增长。

另外,浏览器的存储回收机制对活跃SW持有的资源会更保守,不会主动回收,直到SW被终止或空闲足够久。

解决办法

方案1:删除缓存后重启Service Worker

在message事件的缓存删除完成后,强制触发SW更新并激活新实例,彻底释放旧缓存的引用:

self.addEventListener('message', event => {
  if (event.data.type === 'delete-caches') {
    caches
      .keys()
      .then(keysList => {
        return Promise.all(
          keysList.map(key => {
            console.log(`[SW] Deleting Cache: ${key}`);
            return caches.delete(key);
          })
        );
      })
      .then(() => {
        console.log('[SW] Caches Deleted');
        // 触发SW更新并激活新实例
        return self.registration.update();
      })
      .then(() => {
        return self.skipWaiting();
      })
      .then(() => {
        // 通知客户端刷新,确保新SW接管
        self.clients.matchAll({ includeUncontrolled: true }).then(clients => {
          clients.forEach(client => {
            client.postMessage({ type: 'sw-restarted' });
          });
        });
      })
      .catch(err => {
        console.log('[SW] Deleting Caches Error: ', err);
      });
  }
});

客户端收到sw-restarted消息后,可以主动刷新页面,让新SW完全接管,此时旧SW被终止,浏览器会回收缓存空间。

方案2:模拟版本更新流程(更稳妥)

不直接删除当前活跃的缓存,而是通过切换版本号的方式,复用activate阶段的缓存清理逻辑:

  1. 在message事件中,生成新的版本号(比如自增),并更新缓存名称。
  2. 触发SW更新,新SW安装时使用新版本号创建缓存。
  3. 新SW激活时,自动删除旧版本的缓存,同时旧SW被终止,空间正常回收。

修改后的核心代码示例:

// 初始版本,可通过message事件更新
let currentVersion = 0.01;
let STATIC_CACHE_NAME = `static-v_${currentVersion}`;
let DYNAMIC_CACHE_NAME = `dynamic-v_${currentVersion}`;

// ... 其他生命周期代码不变

self.addEventListener('message', event => {
  if (event.data.type === 'delete-caches') {
    // 生成新版本号并更新缓存名称
    currentVersion += 0.01;
    STATIC_CACHE_NAME = `static-v_${currentVersion}`;
    DYNAMIC_CACHE_NAME = `dynamic-v_${currentVersion}`;
    
    // 触发SW更新,新SW会使用新版本号
    self.registration.update().then(() => {
      console.log('[SW] 触发版本更新,将在激活阶段清理旧缓存');
      self.skipWaiting();
    });
  }
});

这种方式完全复用了已验证有效的activate阶段缓存清理逻辑,避免了活跃SW持有缓存引用的问题,存储空间回收更可靠。

验证方式

执行缓存删除操作后:

  • 查看DevTools的Application > Cache Storage,确认所有缓存已被移除。
  • 等待几秒或刷新页面后,查看Application > Storage > Storage usage by origin,确认存储空间下降。
  • 触发fetch事件,检查是否不会重复积累无效存储。

内容的提问来源于stack exchange,提问作者Manolis Thalassinos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:40:42