如何使用JavaScript fetch在客户端实现API请求临时缓存
原有代码的问题
你写的实现达不到自定义时长临时缓存的效果,核心缺陷有三个:
- 用全局变量存缓存配置和定时器,并发请求时会互相覆盖状态。比如同时发起一个开缓存、一个不开缓存的请求,后执行的请求会直接改掉全局的cache值,导致配置完全错乱。
fetch自带的cache: "force-cache"走的是浏览器标准HTTP缓存逻辑,缓存存多久完全看服务端返回的Cache-Control响应头,客户端没法自己定2秒这种短有效期。- 全局定时器只要有新请求进来就会被重置,根本做不到按单个请求维度计算过期时间。
可落地的客户端缓存实现
要实现完全由客户端控制有效期的临时缓存,最可靠的方式是自己在fetch外层加一层内存缓存逻辑,不依赖浏览器默认缓存规则,缓存键、有效期完全可控,特别适合大体积JSON响应的短时间缓存场景。
核心逻辑:
- 用
Map做缓存存储,每条缓存记录保存响应副本和过期时间戳 - 缓存键由请求方法、路径、参数共同生成,避免不同参数的请求命中错误缓存
- 请求前先查缓存,未过期直接返回缓存内容,过期则发起真实请求,请求成功后把响应副本写入缓存
- 注意要缓存
Response的克隆对象,因为fetch返回的Response是流对象,读取一次就会消耗,直接存原对象会导致缓存命中后拿不到数据
完整实现代码:
// 缓存存储,key为请求唯一标识,value为 { data: 响应克隆对象, expireTime: 过期时间戳 } const requestCache = new Map(); /** * 封装fetch请求,支持客户端自定义时长缓存 * @param {string} path 请求路径 * @param {string} method 请求方法,默认GET * @param {object} params 请求参数,GET请求自动拼为查询参数,其他方法作为请求体 * @param {boolean} allowCache 是否开启临时缓存,默认false * @param {number} cacheTTL 缓存有效期,单位毫秒,默认2000毫秒 * @returns {Promise<Response>} fetch响应对象 */ async function request(path, method = "GET", params = {}, allowCache = false, cacheTTL = 2000) { // 构造唯一缓存key const cacheKey = `${method.toUpperCase()}_${path}_${JSON.stringify(params)}`; // 开启缓存的场景先查缓存 if (allowCache) { const cachedItem = requestCache.get(cacheKey); // 缓存存在且未过期,直接返回缓存的响应克隆 if (cachedItem && Date.now() < cachedItem.expireTime) { return cachedItem.data.clone(); } // 缓存过期就删掉旧记录 requestCache.delete(cacheKey); } // 构造fetch配置 const options = { method: method.toUpperCase(), headers: { "Content-Type": "application/json" } }; // 处理参数:GET拼查询串,其他方法序列化请求体 let requestUrl = path; if (method.toUpperCase() === "GET") { const searchParams = new URLSearchParams(params); requestUrl = `${path}?${searchParams.toString()}`; } else { options.body = JSON.stringify(params); } // 发起真实请求 const response = await fetch(requestUrl, options); // 开启缓存的场景,写入缓存(存克隆对象,避免原响应被读取后缓存失效) if (allowCache && response.ok) { requestCache.set(cacheKey, { data: response.clone(), expireTime: Date.now() + cacheTTL }); // 到期自动清理过期缓存,避免内存无限增长 setTimeout(() => { const currentItem = requestCache.get(cacheKey); if (currentItem && Date.now() >= currentItem.expireTime) { requestCache.delete(cacheKey); } }, cacheTTL); } return response; }
使用说明
- 调用时传
allowCache: true即可开启默认2秒的缓存,需要自定义时长可以传cacheTTL参数,单位为毫秒,比如要缓存1分钟就传60000 - 默认GET请求会把参数自动拼接到URL查询串,非GET请求会把参数序列化为JSON请求体
- 缓存默认存在内存里,页面刷新后会清空,如果需要持久化缓存,可以把存储层换成Cache Storage,核心逻辑不用改
- 非GET请求开启缓存前要确认接口是幂等的,不要把提交、删除类的写操作接口缓存,避免业务异常
内容的提问来源于stack exchange,提问作者user19249111
相关产品推荐
相关产品推荐

