HstarDoc
HstarDoc copied to clipboard
一个缓存异步函数返回值的方法
V1 版本:
import { EventEmitter } from "events";
const bus = new EventEmitter();
// 缓存队列
const cacheMap: Map<
string,
{
status: "pending" | "loading" | "succeed" | "failed";
data?: any;
queue: string[];
}
> = new Map();
async function asyncCache(cacheKey: string, asyncFn: () => Promise<any>) {
// 先初始化缓存
if (!cacheMap.has(cacheKey)) {
cacheMap.set(cacheKey, { status: "pending", queue: [] });
}
const fnId = Math.random().toString(16).slice(2);
// 缓存对象,可直接修改对象属性
let cacheItem = cacheMap.get(cacheKey);
// 有缓存成功的数据,直接返回
if (cacheItem.status === "succeed") {
return cacheItem.data!;
}
// 加入队列
cacheItem.queue.unshift(fnId);
// 有请求中的数据,先加入队列
if (cacheItem.status === "loading") {
await new Promise((resolve) => {
bus.on("ASYNC_DONE", () => {
// 如果数据缓存成功或者队列中轮到自己,就停止等待
if (
cacheItem.status === "succeed" ||
fnId === cacheItem.queue[cacheItem.queue.length - 1]
) {
resolve(1);
}
});
});
}
cacheItem = cacheMap.get(cacheKey);
// 有缓存成功的数据,直接返回
if (cacheItem.status === "succeed") {
return cacheItem.data!;
}
cacheItem.status = "loading";
return Promise.resolve()
.then(() => {
return asyncFn();
})
.then((data) => {
// 记录缓存状态和缓存数据
cacheItem.status = "succeed";
cacheItem.data = data;
return data;
})
.catch((reason) => {
cacheItem.status = "failed";
return Promise.reject(reason);
})
.finally(() => {
// 结束了自己出队
cacheItem.queue.pop();
// 通知其他等待的请求
bus.emit("ASYNC_DONE");
});
}