typescript - promise缓存与复用

1,868 阅读1分钟

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时候面写库包的时候尝试加的

  1. 缓存的是整个promise动作,而不是promise的结果,因为promise的结果需要在promise完成后才会得到,如果此时有多个promise同时发出,并不能复用前一个promise(所以不是等待awit之后再缓存)
  2. 当promise异常时,应该把缓存清掉(也可以有自己的方案),保证下一次调用时没有缓存
  3. 增加了一个删缓存的钩子

测试截图


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)
})();

image.png

可以看到,同时发起的 a和b,只会触发一次promise的内部方法(可以认为就是ajax),而在3秒后,由于promise已经被缓存,此时不会再发起调用而直接服用结果