使用Promise优化带Token缓存的API并发重复请求问题
并发重复请求Token问题优化
现有实现的核心问题
- 首次触发时5-10个同id并发调用同时执行,此时缓存map无数据,所有请求都会独立发起Token获取接口调用,产生大量冗余请求
- 原函数没有返回axios调用的Promise,调用方无法拿到异步请求的最终结果,逻辑本身存在缺陷
优化逻辑
- 新增*Pending Promise(待完成请求Promise)*作为临时缓存,不只缓存最终Token结果
- 同一id的首个请求发起后,立即把未完成的请求Promise存入缓存,后续同id的并发调用直接复用这个Pending Promise,不再重复发起接口请求
- 等首个请求返回成功后,把缓存的Pending Promise替换为最终的Token响应结果;如果请求失败,立刻清空对应的Pending缓存,避免后续同id请求被永久卡住
优化后代码
// 沿用原有已全局定义的缓存map export default (token, id) => { // 已存在最终缓存结果,直接返回token if (map[id] && !(map[id] instanceof Promise)) { return Promise.resolve(map[id]?.token); } // 已存在正在等待的同id请求,直接复用这个Promise,不重复发请求 if (map[id] instanceof Promise) { return map[id]; } // 首个发起的请求,构造请求Promise并存入缓存 const requestTask = axios .post( `https://**********`, { id }, { headers: { Authorization: `Bearer ${token}` } } ) .then(response => { const cacheData = { ...response }; // 请求成功后,把缓存从Pending Promise替换为实际响应数据 map[id] = cacheData; return cacheData.token; }) .catch(err => { // 请求失败清空Pending缓存,保证后续请求可以正常重试 delete map[id]; throw err; }); // 把待完成的请求Promise存入缓存,供后续并发调用复用 map[id] = requestTask; return requestTask; };
优化效果
- 同id的并发请求只会触发1次Token接口调用,所有并发触发的调用都会等待首次请求完成,直接复用最终返回的Token
- 兼容原有缓存逻辑,已经拿到Token的id后续调用直接返回缓存值,不再发起请求
- 增加了异常容错逻辑,请求失败后不会残留无效的Pending缓存,不会影响后续同id的请求重试
注:如果后续需要区分不同token、id组合的缓存,可以在map的key里拼接token和id的字符串,避免不同权限的请求复用同一份缓存。
内容的提问来源于stack exchange,提问作者Varun Sukheja
相关产品推荐
相关产品推荐

