promise单例异步加载的核心是缓存promise实例而非结果值,通过外部变量或map存储并复用同一promise,支持链式调用;可封装为工厂函数,注意错误处理、参数化缓存及闭包变量更新问题。

Promise 实现单例异步加载,核心是“只发起一次请求,后续调用直接复用已有的 Promise”,避免重复请求和资源浪费。
缓存同一个 Promise 实例
关键在于把 Promise 实例保存起来,后续调用不再创建新 Promise,而是返回已缓存的实例。注意:不能缓存 Promise 的结果值(如 data),而要缓存 Promise 对象本身,否则无法链式调用 .then() 或 await。
- 声明一个外部变量(如
let loadingPromise = null)存储正在执行或已完成的 Promise - 每次调用时先判断是否存在缓存的 Promise;有则直接返回,没有则新建并赋值给缓存变量
- 不需要手动处理 resolve/reject 状态同步——Promise 天然支持多次
.then(),且状态不可逆
封装成可复用的工厂函数
把单例逻辑抽离为通用函数,便于在不同资源上复用:
function createSingletonLoader(loaderFn) {
let promise = null;
return function() {
if (!promise) {
promise = loaderFn().catch(err => {
promise = null; // 失败后清空,允许下次重试
throw err;
});
}
return promise;
};
}
// 使用示例
const loadUser = createSingletonLoader(() => fetch('/api/user').then(r => r.json()));
const loadConfig = createSingletonLoader(() => import('./config.js'));
支持参数化与多键缓存(进阶)
如果加载逻辑依赖参数(如 loadUser(id)),需按参数做键映射,避免误共享:
- 用 Map 或普通对象以参数组合为 key 缓存 Promise,例如
cacheMap.set(key, promise) - key 可用
JSON.stringify(args)(仅适用于可序列化参数),或更稳妥地用args.join('_')等简单拼接 - 注意清理策略:长期运行的应用中,可考虑设置 TTL 或 LRU 缓存,防止内存泄漏
常见陷阱与注意事项
容易忽略但影响行为的关键点:
-
不要在 Promise 内部重复赋值:确保
promise = loaderFn()只执行一次,否则会覆盖原引用 -
错误后默认不重试:上面示例中失败时清空
promise,下一次调用会重新发起;若希望“失败也缓存”,去掉promise = null即可 - 避免闭包捕获过期变量:尤其在 React 等框架中,确保 loaderFn 不依赖会变化的 props/state,否则单例可能加载错误数据
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











