PWA中Ajax请求失败时如何访问IndexedDB缓存数据?
处理PWA离线缓存与在线更新的正确姿势
你的思路完全没问题:在线时优先用接口数据并同步更新本地缓存,离线时 fallback 到IndexedDB里的缓存数据。但现有代码里有个核心问题需要修正——异步操作的处理逻辑,因为IndexedDB的读写都是异步的,不能像同步代码那样直接赋值res,否则拿到的会是Promise对象而非实际数据。
先明确两个工具函数的异步特性
首先假设你的getCacheAudits和getServerAudits都是返回Promise的异步函数(如果还不是,建议改成这样,IndexedDB操作一定要用Promise封装,避免回调嵌套的混乱):
getCacheAudits(start, end):查询IndexedDB中指定时间范围的审计数据,resolve返回数据(空数组或有效数据)getServerAudits(audits):将接口返回的审计数据存入IndexedDB,resolve表示缓存写入成功
修正后的getAudits函数
我用async/await重构了代码,让异步逻辑更清晰易懂:
getAudits: async (startOfMonth, endOfMonth) => { try { // 发起在线请求 const response = await request .get(`${url}api/?method=Audit.data`) .query({ pageLength: "all", format: "json", where: startOfMonth ? Utils.hashQuery("a.date", "between", [startOfMonth, endOfMonth].toString()) : "", ts: new Date().getTime() }); // 解析接口返回的数据 const auditRows = JSON.parse(response.text).rows; const audits = Utils.toArray(auditRows); // 如果rows本身是数组,可直接用auditRows替代 // 等待缓存更新完成(确保下次离线能拿到最新数据) await getServerAudits(audits); // 返回接口的最新数据 return audits; } catch (networkError) { // 网络请求失败,尝试读取本地缓存 try { const cachedAudits = await getCacheAudits(startOfMonth, endOfMonth); // 缓存有数据就返回,无数据则返回空数组(可根据业务需求调整) return cachedAudits.length ? cachedAudits : []; } catch (cacheError) { // 缓存读取也失败时,才抛出最终错误 throw new Error(`网络请求失败且缓存读取失败: ${cacheError.message}`); } } }
关键修改点说明
- 改用async/await:替代原来的Promise回调嵌套,代码可读性大幅提升,异步流程更直观。
- 正确处理异步缓存操作:
- 在线成功时,用
await等待getServerAudits完成,确保缓存更新后再返回数据,避免下次离线时拿到旧缓存。 - 离线时,用
await获取getCacheAudits的实际结果,而不是直接赋值(原来的写法会拿到Promise对象,不是真实数据)。
- 在线成功时,用
- 分层错误处理:先捕获网络请求错误,再尝试读取缓存;只有当缓存也读取失败时,才抛出最终错误,避免前端直接无数据可用。
- 简化数据解析:如果接口返回的
rows本身就是数组,Utils.toArray可以省略,直接用JSON.parse(response.text).rows即可。
额外优化建议
- 缓存时间戳:可以在缓存中存储数据的更新时间,下次在线时对比服务器数据的更新时间,避免重复缓存相同内容。
- 缓存失效策略:设置缓存过期时间,超过时限后,即使在线也强制刷新数据,保证缓存时效性。
- Service Worker配合:如果你的PWA使用了Service Worker,可以在请求拦截层面做离线缓存,和IndexedDB的缓存形成互补,进一步提升离线体验。
内容的提问来源于stack exchange,提问作者Rúben Santos
相关产品推荐
相关产品推荐

