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

Angular PWA缓存过大问题最优处理方案咨询

Angular Service Worker 大缓存体积问题的最优解决方案

问题根源分析

当前配置存在两个核心问题:

  • 两个dataGroups使用了相同名称imageStoreCache,导致缓存规则冲突,Angular Service Worker无法正确应用每组的maxSize限制;
  • 仅靠maxSize(条目数量)和maxAge(7天)无法控制总缓存体积——用户每日处理数千张图片/文档,单文件(如PDF)体积可能很大,短时间内就会突破磁盘空间阈值,引发CPU/内存占用异常、更新失败。

最优解决方案

1. 修复重复的DataGroup配置

首先修正重名问题,给两个缓存组分配唯一名称,确保各自的缓存限制生效:

{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": ["/favicon.ico", "/index.html", "/manifest.webmanifest", "/*.css", "/*.js"]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": ["/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"]
      }
    }
  ],
  "dataGroups": [
    {
      "name": "imageStoreCache-detail",
      "urls": ["/api/the-image-store/*/*"],
      "cacheConfig": {
        "maxSize": 50,
        "maxAge": "3d",
        "timeout": "10s",
        "strategy": "performance"
      }
    },
    {
      "name": "imageStoreCache-list",
      "urls": ["/api/the-image-store/*"],
      "cacheConfig": {
        "maxSize": 50,
        "maxAge": "3d",
        "timeout": "10s",
        "strategy": "performance"
      }
    }
  ]
}

这里将maxSize从100降至50,maxAge从7天缩短至3天,可根据实际业务场景调整更合理的数值。

2. 基于Service Worker生命周期的自动缓存清理(优于应用初始化清理)

无需在应用初始化时执行清理,利用Service Worker的activate事件(激活阶段)执行LRU(最近最少使用)清理,既高效又不影响应用启动性能:

创建自定义Service Worker扩展脚本(如src/custom-sw.js),添加以下逻辑:

self.addEventListener('activate', (event) => {
  const MAX_CACHE_SIZE_GB = 2;
  const MAX_CACHE_SIZE_BYTES = MAX_CACHE_SIZE_GB * 1024 * 1024 * 1024;

  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.filter((cacheName) => {
          // 只清理数据缓存组,不清理应用资源缓存
          return cacheName.startsWith('imageStoreCache-');
        }).map((cacheName) => {
          return caches.open(cacheName).then((cache) => {
            return cache.keys().then((keys) => {
              // 按请求时间排序,旧的在前
              keys.sort((a, b) => a.timestamp - b.timestamp);
              let totalSize = 0;

              // 先计算总缓存大小
              return Promise.all(keys.map((key) => {
                return cache.match(key).then((response) => {
                  totalSize += parseInt(response.headers.get('content-length') || 0);
                });
              })).then(() => {
                // 超过阈值则删除旧条目,直到符合限制
                let deleteCount = 0;
                const deletePromises = [];
                while (totalSize > MAX_CACHE_SIZE_BYTES && deleteCount < keys.length) {
                  const keyToDelete = keys[deleteCount];
                  deletePromises.push(
                    cache.delete(keyToDelete).then((deleted) => {
                      if (deleted) {
                        totalSize -= parseInt(response.headers.get('content-length') || 0);
                      }
                    })
                  );
                  deleteCount++;
                }
                return Promise.all(deletePromises);
              });
            });
          });
        })
      );
    })
  );
});

然后在angular.json中配置Angular Service Worker使用该扩展:

"projects": {
  "your-app-name": {
    "architect": {
      "build": {
        "options": {
          "serviceWorker": true,
          "ngswConfigPath": "src/ngsw-config.json",
          "assets": [
            "src/custom-sw.js"
          ]
        }
      }
    }
  }
}

3. 区分资源类型优化缓存策略

将PDF文件与缩略图的缓存规则分开:

  • 缩略图体积小、访问频繁,可保留performance策略,适当放宽限制;
  • 大体积PDF文件可改用freshness策略(优先请求网络,缓存仅作降级),或设置极低的缓存时长/条目数量:
"dataGroups": [
  {
    "name": "thumbnail-cache",
    "urls": ["/api/the-image-store/thumbnails/*"],
    "cacheConfig": {
      "maxSize": 100,
      "maxAge": "7d",
      "timeout": "10s",
      "strategy": "performance"
    }
  },
  {
    "name": "pdf-cache",
    "urls": ["/api/the-image-store/pdf/*"],
    "cacheConfig": {
      "maxSize": 10,
      "maxAge": "1d",
      "timeout": "5s",
      "strategy": "freshness"
    }
  }
]

4. 修复应用更新失败问题

结合Angular的SwUpdate服务,在检测到更新时先清理旧数据缓存,再激活更新:

import { SwUpdate } from '@angular/service-worker';
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class UpdateService {
  constructor(private swUpdate: SwUpdate) {
    this.swUpdate.available.subscribe(async () => {
      // 清理旧数据缓存
      if ('caches' in window) {
        const cacheNames = await caches.keys();
        await Promise.all(
          cacheNames.filter(name => name.startsWith('imageStoreCache-'))
            .map(name => caches.delete(name))
        );
      }
      // 激活更新
      await this.swUpdate.activateUpdate();
      window.location.reload();
    });
  }
}

在应用初始化模块中注入该服务即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 22:49:59