功能总结
BcRequestCacheStore
类实现了一个基于内存的请求缓存机制,主要用于避免重复请求、减少接口调用次数以及提高性能。以下是其主要功能点: 缓存管理:
- 使用
Map
数据结构存储缓存数据 (cache
) 和正在执行的请求 (bcRequestCache
)。 - 每个缓存项包含
value
(缓存值)和expiry
(过期时间),支持 TTL(Time To Live)机制。
请求去重 : - 如果多个并行请求具有相同的 key
,只会发送一次实际请求,其余请求会等待该请求完成并返回结果,避免重复调用接口。
缓存命中与过期检查 : - 在发起请求前,先检查缓存中是否存在对应 key
的数据。 - 如果缓存未过期,则直接返回缓存值;如果已过期,则清理缓存并重新发起请求。
错误处理: - 如果请求失败,会捕获错误并抛出异常,同时不会污染缓存。
缓存清除 : - 提供 clear
方法,用于清空所有缓存数据。
实例化 : - 通过 export const cacheRegStore = new BcRequestCacheStore(5000);
创建了一个全局缓存实例,TTL 设置为 5 秒。
使用示例:
- 调用
cacheRegStore.request
方法时,传入一个唯一标识key
和一个异步请求函数requestFn
。 - 示例中,
key
是动态生成的字符串(如uniq_id_${id}
),requestFn
是调用apiFromServer
的异步函数。
核心逻辑
缓存优先:优先从缓存中获取数据,减少不必要的网络请求。
并发控制 :通过 bcRequestCache
管理正在执行的请求,避免重复调用。
生命周期管理:缓存有明确的过期时间,确保数据的新鲜度。
适用场景 适用于需要频繁调用相同接口且结果在一定时间内不会变化的场景,例如:
- 数据查询接口(如用户信息、配置信息等)。
- 需要限制请求频率的场景。
js
class BcRequestCacheStore {
cache; // 存放请求的函数,结果
ttl; // 缓存过期时间
bcRequestCache: Map<string, Promise<unknown> | null>; // 存放请求的函数,避免同时发送相同请求
constructor(ttl = 60000) {
this.cache = new Map();
this.bcRequestCache = new Map();
this.ttl = ttl;
}
async request(
key: string,
requestFn: (...args: unknown[]) => Promise<unknown>,
) {
// 检查缓存值
if (this.cache.has(key)) {
const { value, expiry } = this.cache.get(key);
// 缓存过期时间检查
if (expiry > Date.now()) {
return value;
}
// 缓存过期清理
this.cache.delete(key);
}
// 判断是否正在执行,是的话就等待, 处理并行请求相同请求的场景,如果已经有一个相同请求真正发送,直接等待它即可,不需要重新创建
if (this.bcRequestCache.get(key)) {
return this.bcRequestCache.get(key);
}
try {
// 发送一个新请求,并加入缓存集合
this.bcRequestCache.set(key, requestFn());
// 获取请求成功的值并加入缓存
const value = await this.bcRequestCache.get(key);
this.cache.set(key, {
value,
expiry: Date.now() + this.ttl,
});
// 请求完成后讲请求缓存集合设置空
this.bcRequestCache.set(key, null);
return value;
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
clear() {
this.cache.clear();
}
}
/** 接口缓存实例*/
export const cacheRegStore = new BcRequestCacheStore(5000);
const res = await cacheRegStore.request(`uniq_id_${id}`, async () => {
let resData = await apiFromServer({
id,
});
return resData;
});