Promise缓存

Posted 秋天1014童话

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise缓存相关的知识,希望对你有一定的参考价值。

背景:

        经过业务长时间打磨,往往会沉淀诸多公用的方法和能力,比如获取用户信息,获取某场景配置信息等。在我们进行可视化搭建页面时,往往会存在多模块调用同一个公用方法的情况,比如这个模块需要进行用户信息展示,那个模块需要判断用户是否符合活动人群。如果全局没做状态管理的话,每调用一次,就会发起一次请求。在大流量的场景下,不但会提升qps,可能触发服务器调用阀值,影响用户体验,同时也很浪费服务器资源,这个时候我们就可以去做一个Promise的缓存。这也是面试经常被多形式问到的问题。

一个普通的异步调用

let times = 1;

const mockRequest = ()=>
    return new Promise((resolve, reject)=>
        setTimeout(()=>
            console.log('执行第'+times+'次');
            let userId = '123';
            times++;
            resolve(userId);
        , 3000)
    )


const doMoreRequest = () =>  //执行多次
    mockRequest().then(res=>
        console.log('res1:', res)
    )
    mockRequest().then(res=>
        console.log('res2:', res)
    )

结果:

执行第1次
res1: 123
执行第2次
res2: 123

promise缓存的模拟简化代码:

获取了用户信息之后将promise结果记录在缓存中。因为用户信息在h5活动场景下一般固定(换绑账号等情况除外),此处使用对象值存储。如果有多个key/value值,可以使用map。

let times = 1;
let promiseCache = null; // 此处值固定,如果有个key/value值,可以使用map

const mockRequest = ()=>
    return new Promise((resolve, reject)=>
        setTimeout(()=>
            console.log('执行第'+times+'次');
            let userId = '123';
            times++;
            resolve(userId);
        , 3000)
    )



const mockRequestMemoize = ()=>
    if (!promiseCache) 
        const userPromise = mockRequest();
        promiseCache = userPromise; // 获取了用户信息之后将promise结果记录在缓存中
    
    
    return promiseCache;


const doMoreRequestMemoize = () =>  //模拟执行多次
    mockRequestMemoize().then(res=>
        console.log('res1:', res)
    )
    mockRequestMemoize().then(res=>
        console.log('res2:', res)
    )
    setTimeout(()=>
        mockRequestMemoize().then(res=>
            console.log('res3:', res)
        )
    , 2000)


doMoreRequestMemoize();

结果:

结果:
执行第1次
res1: 123
res2: 123
res3: 123

为什么是缓存promise,而不是缓存结果?

如果是缓存结果,那么需要第一个调用拿到请求结果后,才会记录缓存,但当此时,再来第二个请求,将会再次发起请求。

无论时间如何,当我们对进行多次调用时,只会触发一个网络请求。这是因为所有后续调用者都收到与第一个相同的 Promise 单例。

错误处理

除了正常接口返回,还应考虑接口失败的可能性。如果已缓存了被拒绝的 Promise ,则所有将来的调用都将以同样的失败 Promise 被拒绝。

let times = 1;
let promiseCache = null;

const mockRequest = ()=>
    return new Promise((resolve, reject)=>
        setTimeout(()=>
            console.log('执行第'+times+'次');
            let userId = '123';
            times++;
            reject(userId); // 此处拒绝返回
        ,3000) 
    )


const mockRequestMemoize = ()=>
    if (!promiseCache) 
        const userPromise = mockRequest();
        promiseCache = userPromise;
    
    
    return promiseCache;


const doMoreRequestMemoize = () =>  //模拟执行多次
    mockRequestMemoize().then(res=>
        console.log('res1:', res)
    ).catch(err=>
        console.log('err1:', err)
    )
    mockRequestMemoize().then(res=>
        console.log('res2:', res)
    ).catch(err=>
        console.log('err2:', err)
    )
    setTimeout(()=>
        mockRequestMemoize().then(res=>
            console.log('res3:', res)
        ).catch(err=>
            console.log('err3:', err)
        )
    , 2000)


doMoreRequestMemoize();

结果:

执行第1次
err1: 123
err2: 123
err3: 123

## 

参考

以上是关于Promise缓存的主要内容,如果未能解决你的问题,请参考以下文章

Promise缓存

Request-Promise:承诺缓存结果

在expressJS中如何创建一个缓存,使多个请求等待相同的promise [重复]

手写基于Promise A+规范的Promise

在Service Worker中抛出错误“Uncaught(in promise)DOMException”

Promise.all 的 then() 函数在 Promise 完成之前执行 - Ionic/Angular