once-Promise

场景

有这么一种场景,一个页面两个组件都需要从后端获取配置数据,于是两个组件都发起了同样的请求;于是本来只需要进行一次的请求就变成了两次。
解决这个问题的办法有很多,把请求放到父组件等等,这里介绍另一种做法。

方案

模拟异步请求

// 一个异步计数方法,每次调用 count 会加1
var f = (function(){
    let count = 0
    return function (){
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(count ++)    
                 console.log('count:',count)
            },1000)
        }) 
    }
})()

进行尝试

于是我们先写了这样的代码,看下返回结果

;(async()=>{
     await f()
})()
;(async()=>{
     await f()
})()
// 打印结果
// count:1
// count:2

调用了两次,返回了不同的结果。

明确目的

我们希望的是两次调用,返回相同的结果。
思路:连续调用异步函数 f 时,如果 上一个 f 还没执行完成,则当前调用不新建新的异步任务,直接复用上次任务即可。

one-promise 方法

const oncePromise = 
(fn, p = null) =>
    (...arg) =>
        p ? p : (p = fn(...arg).finally(() => (p = null)));

有了 one-promise 方法后,我们可以这样做

var f1 = oncePromise(f)
;(async()=>{
     await f1()
})();(async()=>{
     await f1()
})()
// 打印 
// count: 1

PS: 因为 console 语句是写在 f 这个异步方法里的,所以虽然执行了两次 f1 也只会打印出一次 count:1
(因为oncePromise 中,如果 上一个任务存在,就不会开始新的任务了)

整体测试代码

const oncePromise = 
(fn, p = null) =>
    (...arg) =>
        p ? p : (p = fn(...arg).finally(() => (p = null)));

var f = (function(){
    let count = 0
    return function (){
        return new Promise(resolve=>{
            setTimeout(()=>{
                resolve(count ++)    
                 console.log('count:',count)
            },1000)
        }) 
    }
})()

var f1 = oncePromise(f)
;(async()=>{
     await f1()
})();(async()=>{
     await f1()
})()
Comments
Write a Comment