fetch 本身不提供离线缓存能力,但可结合 cache api(service worker 环境)实现标准 pwa 离线方案:install 阶段预缓存、fetch 阶段缓存优先并后台更新、activate 阶段清理旧缓存。

fetch 本身不提供离线缓存能力,但可以结合 Cache API(Service Worker 环境下)或 localStorage / IndexedDB(主页面环境)实现降级:网络失败时读取本地缓存数据。
用 Cache API + Service Worker 实现自动缓存与降级
这是最标准的 PWA 离线方案,适合静态资源和结构化 API 响应:
- 在 Service Worker 中监听
fetch事件,对匹配的 API 请求先尝试从caches.match()读缓存 - 若缓存命中,直接返回;未命中则发起真实请求,并在响应成功后用
caches.put()存入缓存 - 网络异常(如
TypeError: Failed to fetch)时,主动 fallback 到缓存——即使缓存过期也比白屏强 - 注意:需在响应中设置
Cache-Control: no-store或手动忽略它,避免浏览器强缓存干扰逻辑
在页面脚本中用 localStorage 模拟简单降级
适合轻量、非敏感、结构简单(如配置、列表页数据)的场景,无需 Service Worker:
- 发送 fetch 前,先从
localStorage.getItem(key)读取上一次缓存的数据(含时间戳) - fetch 成功后,把新数据连同
Date.now()一起序列化存入:localStorage.setItem(key, JSON.stringify({ data, ts })) - fetch 失败时,检查缓存是否“不过期”(例如 5 分钟内),是则解析并返回;否则返回空/默认值或提示“暂无网络”
- 缺点:localStorage 有大小限制(通常 5–10MB)、不支持二进制、无事务,不适合大文件或高频更新数据
用 IndexedDB 实现可靠结构化缓存
适合需要存储较大数据(如用户历史、离线文章)、支持查询、多 tab 同步的场景:
- 封装一个基于
idb库(或原生 IDB)的缓存工具,提供get(key)/set(key, value, ttl?) - fetch 请求包装为异步函数:先查 IndexedDB → 命中且未过期则 resolve 缓存;再发网络请求 → 成功则更新 DB 并 resolve 新数据;失败则只返回缓存(或 reject)
- 可加版本控制字段,避免旧版前端读到新版数据结构导致解析错误
- 比 localStorage 更健壮,但写法稍复杂,建议用
idb这类 Promise 封装库简化操作
关键细节与避坑提醒
无论选哪种方式,都要注意:
- 缓存键设计要包含 URL + 查询参数 + 可能的 headers(如 Accept),避免不同条件共用同一缓存
- 不要缓存 4xx/5xx 响应,否则下次会返回错误状态码,造成“假成功”
- 区分“首次加载”和“刷新加载”:首次无缓存时,可展示骨架屏+loading,而不是强行 fallback
- 用户登出或数据强一致性要求高时,记得清理对应缓存,避免脏数据
- 开发阶段可在 DevTools 的 Application → Cache / Storage 面板里手动清空验证逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











