在Workbox precacheAndRoute中用异步回调确定缓存资源时遇报错如何解决?
问题:Workbox precacheAndRoute 缓存IndexedDB文件路径报错
additionalURLs is not iterable 我在Service Worker中使用workbox-precaching的precacheAndRoute方法,希望缓存IndexedDB中已存在的、因用户而异的文件路径,代码如下:
import { precacheAndRoute } from 'workbox-precaching'; import localforage from "localforage"; let formID; const cachedFilesStore = localforage.createInstance({ name: 'page-id', storeName: 'store' }) const produceValuesFromCache = () => { return cachedFilesStore.getItem('1') .then(async (value) => { formID = formID || value.form_id; const cachedFiles = await cachedFilesStore.getItem(`${formID}`) return [ ...cachedFiles.manifest, `/form/${formID}` ] }); } precacheAndRoute([], { urlManipulation: async ({ url }) => { const files = await produceValuesFromCache(); return files } })
执行后未达到预期效果,反而出现报错:Uncaught TypeError: additionalURLs is not iterable。另外,将文件存入IndexedDB的代码位于路由form/${formID}下的index.html文件中。
错误原因及解决方法
核心错误点
- 误用
urlManipulation回调:这个回调的作用是处理请求时的URL重定向逻辑(比如将旧路径映射到新路径),不是用来动态添加预缓存项的。预缓存是在Service Worker的install阶段执行的,你在请求阶段才去IndexedDB获取数据,时机完全不对。 - 返回格式不符合要求:
urlManipulation要求返回Array<Array<URL>>类型(外层数组是重定向选项组,内层数组是具体的URL对象数组),你直接返回了字符串路径数组,Workbox尝试遍历每个字符串时触发了“不可迭代”的错误。
正确实现思路
要动态预缓存IndexedDB中的文件,需要在Service Worker的install事件中完成以下步骤:
- 从IndexedDB读取目标文件路径
- 整理成Workbox预缓存接受的格式
- 调用
precacheAndRoute执行预缓存
修正后的代码
import { precacheAndRoute } from 'workbox-precaching'; import localforage from "localforage"; const cachedFilesStore = localforage.createInstance({ name: 'page-id', storeName: 'store' }); // 在install事件中完成动态预缓存 self.addEventListener('install', async (event) => { try { // 从IndexedDB获取formID const idData = await cachedFilesStore.getItem('1'); if (!idData?.form_id) { console.log('未找到formID,跳过动态预缓存'); return; } const formID = idData.form_id; // 获取需要缓存的文件清单 const cachedFiles = await cachedFilesStore.getItem(`${formID}`); if (!cachedFiles?.manifest) { console.log('未找到缓存文件清单'); return; } // 整理预缓存项:转为Workbox接受的格式,支持字符串或{url: string}对象 const precacheList = [ ...cachedFiles.manifest, `/form/${formID}` ]; // 执行预缓存 precacheAndRoute(precacheList); // 强制等待安装完成后激活新的Service Worker(可选) self.skipWaiting(); } catch (error) { console.error('动态预缓存失败:', error); } }); // 如果有静态预缓存清单(比如通过workbox-build生成的),可以合并进来 // precacheAndRoute(self.__WB_MANIFEST);
额外注意事项
- 当IndexedDB中的缓存路径更新时,需要触发Service Worker更新(比如修改Service Worker文件内容、添加版本注释),否则旧的预缓存清单不会自动更新。
- 激活新Service Worker后,可以调用
self.clients.claim()让所有已打开的页面立即使用新的Service Worker(可选,需在activate事件中添加)。
内容的提问来源于stack exchange,提问作者lordsarcastic
相关产品推荐
相关产品推荐

