promise本身不提供缓存或超时能力,但可通过map缓存promise实例、settimeout定时清理、手动管理timerid实现带超时自动清理的异步缓存,核心是缓存promise而非结果,并在过期后从map中删除键值对。

Promise 本身不提供缓存或超时能力,但可以组合 Promise、Map、setTimeout 和取消逻辑,手动构建一个带超时自动清理的异步缓存。核心思路是:缓存 Promise 实例(不是结果),并为每个缓存项绑定过期定时器;当缓存命中时复用未 reject/resolved 的 Promise;过期后自动从缓存中移除,下次请求重新发起。
缓存结构设计:用 Map 存储 Promise + 过期时间
用 Map 以请求键(如 URL 或参数序列化字符串)为 key,value 是一个对象,包含:
- promise:正在执行或已 settled 的 Promise 实例
- expiresAt:毫秒级时间戳,表示该缓存项的过期时刻
- (可选)timerId:用于 clearTimeout,避免内存泄漏
- 每次 get 前先检查是否过期,过期则删除并返回 undefined
- set 时启动定时器,在到期时自动 delete 该 key(注意:不能直接 reject Promise,因为可能已有 .then 链在等待)
- 不缓存最终值,只缓存 Promise,保证并发请求共享同一执行过程
实现超时销毁:定时清理 + 缓存键隔离
超时不是“中断 Promise”,而是让缓存失效。真正执行的异步操作(如 fetch)仍会完成,但其结果不再被后续 get 使用。关键点:
- 设置缓存 TTL(例如 5000ms),写入 Map 时记录
Date.now() + ttl - 在 get 时判断
expiresAt ,若过期,<code>map.delete(key)并返回 null/undefined - 为避免定时器堆积,每次 set 时先 clear 旧 timer(如果存在),再 set 新 timer
- 注意:不能用
AbortController替代缓存超时——那是请求级取消,和缓存生命周期无关
封装成可复用的 Cache 类
下面是一个轻量实现示例(无外部依赖):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
class AsyncCache {
constructor(ttl = 5000) {
this.cache = new Map();
this.ttl = ttl;
}
<p>get(key) {
const item = this.cache.get(key);
if (!item) return undefined;
if (item.expiresAt </p><p>set(key, promise) {
// 清理旧定时器
if (this.cache.has(key)) {
clearTimeout(this.cache.get(key).timerId);
}
const expiresAt = Date.now() + this.ttl;
const timerId = setTimeout(() => {
this.cache.delete(key);
}, this.ttl);
this.cache.set(key, { promise, expiresAt, timerId });
}</p><p>// 可选:手动清除
delete(key) {
const item = this.cache.get(key);
if (item) clearTimeout(item.timerId);
this.cache.delete(key);
}
}</p>
使用方式:
const cache = new AsyncCache(10000); // 10秒缓存
<p>async function fetchData(url) {
const cached = cache.get(url);
if (cached) return cached;</p><p>const promise = fetch(url).then(r => r.json());
cache.set(url, promise);
return promise;
}</p>
注意事项与边界处理
实际使用中需留意几个细节:
- Promise 状态不可逆:即使缓存过期,已 resolve/reject 的 Promise 仍有效;缓存机制只是决定“是否复用”,不改变 Promise 行为
- 错误不自动过期:fetch 失败的 Promise 也会被缓存,建议根据业务决定是否缓存 reject(例如重试场景可缓存失败,防抖场景应跳过)
- 键要稳定可比较:对象参数需 JSON.stringify 或自定义 key 生成函数,避免引用不同但内容相同的键被重复请求
- 内存泄漏风险:长时间运行需监控 Map size,必要时加 LRU 限制或定期清理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










