前言
前端经常要用到缓存,比如现在有个需求,每次重复调用接口(包括连续调用接口,第一个接口还未返回结果)都只执行一次。一般我们会做api级别的缓存,但是无法满足连续调用接口,第一个接口还未返回结果时,仍然只执行一次的要求。
实现
/** * 内存缓存,采用LRU算法 */
export default class LRUCache {
// 缓存数据
static cache = new Map()
// 最大容量,容量小于等于0时,表示不使用内存缓存
static capacity = 100
// 设置缓存容量
static setCapacity(capacity) {
if (typeof capacity === 'number') {
LRUCache.capacity = capacity
}
}
// 从缓存中取值
static get(key) {
if (LRUCache.cache.has(key)) {
const temp = LRUCache.cache.get(key)
// 访问到的 key 若在缓存中,删除原来的值,放到尾部
LRUCache.cache.delete(key)
LRUCache.cache.set(key, temp)
return typeof temp === 'object' ? JSON.parse(JSON.stringify(temp)) : temp
}
return ''
}
// 将值写入缓存
static put(key, value) {
// 容量小于等于0时,表示不使用内存缓存
if (LRUCache.capacity <= 0) {
return
}
if (LRUCache.cache.has(key)) {
// 存在则删除
LRUCache.cache.delete(key)
} else if (LRUCache.cache.size >= LRUCache.capacity) {
// 超过缓存长度,淘汰最近没使用的 第一个
LRUCache.cache.delete(LRUCache.cache.keys().next().value)
console.log(`LRUCache refresh: key:${key} , value:${value}`)
}
LRUCache.cache.set(key, typeof value === 'object' ? JSON.parse(JSON.stringify(value)) : value)
}
// 从缓存中移除
static delete(key) {
if (LRUCache.cache.has(key)) {
// 存在则删除
LRUCache.cache.delete(key)
}
}
// 查看内存缓存
static showCache() {
console.log('LRUCache capacity:', LRUCache.capacity)
console.log('LRUCache cache:', LRUCache.cache)
// 打印出 Map 中的信息
// LRUCache.cache.forEach((value, key) => console.log(`LRUCache.cache key: ${JSON.stringify(key)} ,value: ${JSON.stringify(value)}`))
}
}
// 函数执行映射关系,执行完成后清除
const cacheKeyMap = new Map()
/**
* @desc 缓存函数执行结果,防止重复执行某个函数
* @param {*} func 待执行的函数
* @param {*} cacheKey 缓存key,判断func是否重复的唯一标识,如果是接口请求,建议拼接请求参数标识唯一性
* @param {*} cacheCondition 缓存条件函数,用于判断func结果是否存入缓存
*/export function cacheFuncResult(func, cacheKey, cacheCondition) {
if (!func || typeof func !== 'function' || !cacheKey) {
return Promise.reject()
}
// 先判断缓存里有没有
const cacheResult = LRUCache.get(cacheKey)
if (cacheResult) {
return Promise.resolve(cacheResult)
}
// 判断执行映射关系里是否有当前函数在执行
if (cacheKeyMap.has(cacheKey)) {
return cacheKeyMap.get(cacheKey)
}
const promise = new Promise((resolve, reject) => {
const result = func()
if (typeof result.then === 'function') {
result
.then(res => {
// console.log('cacheFuncResult 异步函数执行成功:', res)
if (typeof cacheCondition === 'function' && cacheCondition(res)) {
// console.log('cacheFuncResult 存入缓存:', cacheKey)
LRUCache.put(cacheKey, res)
}
// 执行完成,清除执行映射关系
cacheKeyMap.delete(cacheKey)
resolve(res)
})
.catch(e => {
// 执行完成,清除执行映射关系
cacheKeyMap.delete(cacheKey)
reject(e)
})
} else {
// console.log('cacheFuncResult 同步函数执行:')
if (typeof cacheCondition === 'function' && cacheCondition(result)) {
LRUCache.put(cacheKey, result)
}
// 执行完成,清除执行映射关系
cacheKeyMap.delete(cacheKey)
resolve(result)
}
})
// 存入执行映射关系
cacheKeyMap.set(cacheKey, promise)
return promise
}