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
相关产品推荐
相关产品推荐

