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