PWA离线缓存优化咨询:900项静态资源安装过慢问题
大资源量PWA离线缓存优化问题
我有一个需100%离线可用的PWA,包含400个HTML页面、450张PNG内容图片及常规站点资源,总缓存大小为21MB,且内容几乎不会变更。我的Service Worker代码如下:
const all_assets = [...nnc, ...nc, ...checklist_content, ...info, ...fonts, ...other] var cacheName = "ecl-cache-005" self.addEventListener('install', function (event) { event.waitUntil((async () => { const cache = await caches.open(cacheName); await cache.addAll(all_assets); })()); }); self.addEventListener('activate', (e) => { e.waitUntil(caches.keys().then((keyList) => { return Promise.all(keyList.map((key) => { if (key === cacheName) { return; } return caches.delete(key); })) })); }); self.addEventListener('fetch', function (event) { event.respondWith( // Try the cache caches.match(event.request).then(function (response) { // return it if there is a response,or else fetch again return response || fetch(event.request); }) ); });
应用虽能正常运行,但install事件执行极慢,推测是由于Service Worker中需请求的URL数量庞大或19MB的图片资源导致,或两者皆有。请问是否有更优的离线实现方案?能否在install事件完成后单独缓存图片资源?我曾调研过Firestore和IndexedDB方案,但认为它们不兼容图片内容。
优化方案
1. 拆分缓存:install后单独缓存图片
完全可以在install事件完成后再缓存图片,这样能让Service Worker快速完成安装激活,不阻塞核心功能可用。具体思路:
- 将资源拆分为核心资源(HTML、字体、基础脚本等,是页面运行必需的)和非核心资源(图片)
- install阶段只缓存核心资源,确保快速完成安装流程
- 在activate事件中启动图片的后台缓存,不影响用户使用
修改后的示例代码:
const core_assets = [...nnc, ...nc, ...checklist_content, ...info, ...fonts] const image_assets = [...other] // 假设此处为所有图片资源集合 const cacheName = "ecl-cache-005" const imageCacheName = "ecl-images-001" self.addEventListener('install', function (event) { event.waitUntil((async () => { const cache = await caches.open(cacheName); await cache.addAll(core_assets); // 跳过等待,提前激活Service Worker self.skipWaiting(); })()); }); self.addEventListener('activate', (e) => { e.waitUntil((async () => { // 激活后立即接管所有客户端页面 await self.clients.claim(); // 分批次缓存图片,避免单次发起过多请求阻塞浏览器 const imageCache = await caches.open(imageCacheName); const batchSize = 50; for (let i = 0; i < image_assets.length; i += batchSize) { const batch = image_assets.slice(i, i + batchSize); await imageCache.addAll(batch); } // 清理旧缓存 const keyList = await caches.keys(); await Promise.all(keyList.map((key) => { if (key !== cacheName && key !== imageCacheName) { return caches.delete(key); } })); })()); }); self.addEventListener('fetch', function (event) { event.respondWith( caches.match(event.request).then(function (response) { // 先查核心资源缓存,再查图片缓存 if (response) return response; return caches.open(imageCacheName).then(cache => { return cache.match(event.request) || fetch(event.request); }); }) ); });
2. 其他辅助优化措施
- 分批次缓存核心资源:即使是核心资源,也可以分批次调用
cache.addAll(),避免单次发起几百个请求导致浏览器请求队列阻塞 - 资源压缩:对PNG图片进行无损压缩,减少总体积,加快下载速度
- 优先缓存高频资源:如果部分HTML或图片是用户高频访问的,可以优先缓存这部分,剩余资源在后台逐步缓存
- 去重资源列表:检查
all_assets数组,确保没有重复URL,减少不必要的请求
关于IndexedDB的补充:其实IndexedDB支持存储图片Blob,但对于静态资源来说,Cache Storage本身就是更适配的方案,拆分缓存完全可以解决你的问题,不需要额外引入IndexedDB。
内容的提问来源于stack exchange,提问作者Sayed Ali
相关产品推荐
相关产品推荐

