20221228 更新
function CachePromise<T extends any[], R extends any>(fn: (...args: T) => Promise<R>) {
let cache: any = undefined
return async function (...args: T): Promise<R> {
return cache = cache || (() => {
return fn(...args).catch(e => {
cache = undefined;
return Promise.reject(e);
});
})();
}
}
const getMemberInfo = CachePromise(()=> ajax.get('/apis/memberinfo'))
type TPromiseFunction = (...args: any) => Promise<any>
function cachePromise<T extends TPromiseFunction>(promise: T): ReturnType<T> {
let cache = undefined;
let fn = function (...args) {
return cache = cache || promise.apply(this, args)
.catch((error) => {
// 在异常时清除缓存,保证下一次重新调用程序时会再发起
cache = undefined;
return Promise.reject(error);
})
};
fn.deleteCache = ()=> cache = undefined
return fn
}
上面这个代码用了三四年了,ts时候面写库包的时候尝试加的
- 缓存的是整个promise动作,而不是promise的结果,因为promise的结果需要在promise完成后才会得到,如果此时有多个promise同时发出,并不能复用前一个promise(所以不是等待awit之后再缓存)
- 当promise异常时,应该把缓存清掉(也可以有自己的方案),保证下一次调用时没有缓存
- 增加了一个删缓存的钩子
测试截图
function cachePromise(promise) {
let cache = undefined;
let fn = function (...args) {
return (cache =
cache ||
promise.apply(this, args).catch((error) => {
cache = undefined;
return Promise.reject(error);
}));
};
fn.deleteCache = ()=> cache = undefined
return fn
}
let sleep = (ms)=> new Promise(resolve => setTimeout(resolve, ms))
let fn = cachePromise(()=>{
return new Promise(resolve=>{
console.info('call ', new Date)
resolve(new Date)
})
})
;(async()=>{
const a = await fn()
const b = await fn()
console.info(a == b)
await sleep(3000)
const c = await fn()
console.info(a == c)
fn.deleteCache()
const d = await fn()
console.info(a == d)
})();
可以看到,同时发起的 a和b,只会触发一次promise的内部方法(可以认为就是ajax),而在3秒后,由于promise已经被缓存,此时不会再发起调用而直接服用结果