
本文介绍如何通过 promise 缓存机制,确保一个可选的异步请求(如 fetch)在多处调用时最多只发起一次,避免重复网络开销,同时保持代码简洁与线程安全。
本文介绍如何通过 promise 缓存机制,确保一个可选的异步请求(如 fetch)在多处调用时最多只发起一次,避免重复网络开销,同时保持代码简洁与线程安全。
在现代前端开发中,常需根据多个前置条件动态触发同一后端接口(例如:URL c 仅在 a 或 b 的响应满足特定条件时才需调用)。若不加协调,多个条件同时成立将导致重复请求——不仅浪费带宽与服务端资源,还可能因响应时序不同引发数据不一致或竞态问题。
核心思路是:将对 c 的请求封装为一个“惰性求值且幂等”的 Promise 工厂函数,首次调用时发起真实 fetch 并缓存其返回的 Promise;后续调用直接复用该 Promise,天然共享同一 resolve 结果,无需手动处理状态同步或锁机制。
以下为推荐实现方案:
let cPromise;
const fetchC = () => {
// 使用 Nullish Coalescing Assignment (??=) 实现首次赋值保护
// 仅当 cPromise 为 null/undefined 时执行右侧表达式
return (cPromise ??= fetch('c')
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
);
};
// 调用方逻辑保持清晰、解耦
fetch('a')
.then(r => r.json())
.then(data => {
if (data.value === '1') {
fetchC().then(result => console.log('through a', result));
}
});
fetch('b')
.then(r => r.json())
.then(data => {
if (data.value === '1') {
fetchC().then(result => console.log('through b', result));
}
});✅ 关键优势说明:
立即学习“Java免费学习笔记(深入)”;
- 真正单次执行:fetch('c') 最多调用一次,无论 fetchC() 被调用多少次;
- 自动结果共享:所有 .then() 都订阅同一个 Promise,获得相同解析值(含错误);
- 零竞态风险:基于 Promise 的微任务队列机制,天然保证时序一致性;
- 轻量无依赖:仅需 ES2021+ 环境(??= 运算符),无第三方库;
⚠️ 注意事项:
- 若需支持旧版浏览器(如 IE),可将 ??= 替换为传统条件判断:
return cPromise || (cPromise = fetch('c').then(r => r.json())); - 缓存的 Promise 不可重试:一旦 fetch('c') 拒绝(如网络失败),cPromise 将持有一个 rejected Promise,后续调用均立即失败。如需容错重试,应封装更健壮的策略(例如:引入 retry 逻辑或使用 AbortSignal 控制超时);
- 此模式适用于「结果不变」的只读请求;若 c 接口语义上允许缓存但需定期刷新,应在业务层增加 TTL 或显式重置 cPromise 的机制。
总结而言,利用 JavaScript 原生 Promise 的生命周期特性 + ??= 的惰性赋值能力,即可优雅解决“多点触发、单次执行”的常见异步协调问题——无需复杂状态管理,代码简洁、性能可靠、语义清晰。










