OpenPWAStore
返回 News
Guide · May 19, 2026

缓存存储清理规则决定你的 PWA 是否能在存储压力下幸存

你的 PWA 的缓存内容可能被清理。以下是如何决定,以及如何让你的应用具有韧性。

OpenPWA Editorial2 min read
缓存存储清理规则决定你的 PWA 是否能在存储压力下幸存 cover

为什么这很重要

浏览器维护各自的存储预算和清理策略。当存储压力来袭时——磁盘空间不足、用户操作、定期清理——你的 PWA 缓存的资产可能会在没有警告的情况下被清理。如果你的应用需要缓存的内容在离线时使用,而该内容被静默清理,你的离线功能就会中断。用户会责怪你的应用,而不会理解是浏览器存储策略执行的。

缓存存储层

Cache Storage 是你的 Service Worker 存储响应的地方:

const cache = await caches.open('v1');
await cache.addAll([
  '/',
  '/styles.css',
  '/scripts.js',
  '/images/logo.png'
]);

它位于浏览器存储空间中,与 IndexedDB、Web Storage(localStorage/sessionStorage)和其他 API 一起。

浏览器清理策略

Chrome:

  • 使用"清理压力"模型
  • 在同源存储中使用最近最少使用(LRU)清理
  • 当存储限制达到时清理整个源
  • 清理阈值:约占所有浏览器源磁盘空间的 50-60%

Firefox:

  • 使用 LRU 逻辑的每源清理
  • 在磁盘空间较少时更积极
  • 可以清理甚至活动 PWA 的缓存
  • 用户可以从设置中手动清除站点数据

Safari:

  • 以激进的缓存清理而闻名,特别是在 iOS 上
  • 定期清理会自动删除旧缓存
  • iStorage 比 Cache Storage 更容易被清理
  • TWA 包(针对 Android)由于原生包装而具有更好的持久性

存储压力触发因素

浏览器因以下原因清理存储:

  1. 磁盘空间不足 - 当设备有不到约 100MB 的空间时
  2. 用户清除站点数据 - 浏览器设置中的手动操作
  3. 定期维护 - Safari 和 Firefox 清理旧缓存
  4. 超过存储配额 - 你的应用尝试存储超过允许的内容

你无法阻止触发因素 1、3 和 4。你只能设计韧性。

检测与估计

Storage Manager API:

const estimate = await navigator.storage.estimate();
console.log(`配额: ${estimate.quota} bytes`);
console.log(`使用量: ${estimate.usage} bytes`);
console.log(`使用百分比: ${Math.round(estimate.usage / estimate.quota * 100)}%`);

持久化授予:

navigator.storage.persist().then((persistent) => {
  if (persistent) {
    console.log('存储持久化已授予');
  } else {
    console.log('持久化被拒绝 - 数据可能被清理');
  }
});

即使授予了持久化,清理仍然可能发生——只是可能性降低。

幸存策略

保持缓存精简:

  • 只缓存离线功能必需的内容
  • 对可以重新获取的内容使用临时缓存(不持久化)
  • 实现缓存版本控制以删除旧版本
// 删除旧缓存版本
const cacheNames = await caches.keys();
for (const name of cacheNames) {
  if (name !== currentCacheName) {
    await caches.delete(name);
  }
}

检测并从清理中恢复:

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then(async (cacheNames) => {
      // 检查我们的预期缓存是否存在
      const hasCache = cacheNames.includes(currentCacheName);
      if (!hasCache) {
        // 缓存被清理,重新填充它
        return caches.open(currentCacheName).then((cache) => {
          return cache.addAll(essentialAssets);
        });
      }
    })
  );
});

实现回退到网络:

当缓存内容缺失时,从网络获取并更新缓存:

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      if (response) {
        return response;
      }
      return fetch(event.request).then((response) => {
        // 为下次缓存新响应
        return caches.open(currentCacheName).then((cache) => {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

清理评估标准

使用此检查清单评估风险:

| 因素 | 低风险 | 中风险 | 高风险 | |--------|---------|---------|---------| | 缓存大小 | < 10MB | 10-50MB | > 50MB | | 内容类型 | 仅静态资产 | 混合内容 | 用户生成的临时数据 | | 用户参与度 | 每日活跃 | 每周活跃 | 每月活跃 | | 平台 | Android(原生包) | 桌面 | iOS Safari |

高风险 + 不明确的回退 = 用户的离线体验中断。

监控缓存健康状况

在生产环境中追踪这些指标:

  • 缓存命中率(有多少次获取从缓存提供)
  • 关键资产的缓存未命中率
  • 存储配额百分比随时间变化
  • 清理检测(当预期缓存消失时)
  • 重新缓存成功率

当以下情况时向开发人员发出告警:

  • 缓存命中率降至 80% 以下
  • 存储使用量持续超过配额的 70%
  • 检测到关键缓存的清理

对开发者的建议

缓存清理是不可避免的。优雅地处理它,而不是试图阻止它。离线可靠性不是关于防止清理——而是关于检测它并透明地恢复。

将缓存存储视为易失性的。在 Service Worker 激活时实现重新缓存逻辑。设计页面使其在缓存内容缺失时也能工作(显示加载状态、按需获取、提供回退 UI)。

下一步

  1. 在你的安装/激活处理程序中实现缓存清理检测
  2. 将 Storage Manager API遥测添加到你的错误追踪
  3. 设计缓存必需资产与缓存可选资产
  4. 通过手动清除缓存并观察行为来测试清理场景
  5. 为值班工程师编写缓存恢复计划

你的 PWA 应该在缓存清理中幸存,而不是因为它而失败。