前端并发——基于 Promise.race 实现异步并发控制
利用 Promise.race 可以处理执行最快的 Promise 对象这个特性,可以初始化一个大小为并发数的执行池用 race 执行。
有执行池就需要替换掉已经执行完成的任务。只要在执行后加一个 then 方法返回当前任务的数组下标就可以进行替换处理。
function creator(count) {
const arr = [];
let flag = true;
function setup(fn) {
arr.push(fn);
// 包一层异步,让同步调用全部进来
flag && setTimeout(() => {
// 并发执行容器,初始化长度为 count
const promises = arr.splice(0, count).map((item, index) => {
// 返回下标,用于执行容器的替换
return item().then(() => index);
})
// 真正执行过程开始,此时 arr 中为第一轮排不上的异步任务
arr.reduce((pres, curFn) => {
return pres.then(() => {
return Promise.race(promises); // 返回先完成的下标
}).then(fastestIndex => {
// 要继续将这个下标返回,以便下一次遍历
promises[fastestIndex] = curFn().then(() => fastestIndex);
})
}, Promise.resolve());
}, 0) && (flag = false);// flag 控制异步只调用一次
}
return setup
}
const setup = creator(2)
setup(fn)
setup(fn)
setup(fn)
setup(fn)
setup(fn)
function fn() {
return new Promise((resolve) => {
setTimeout(() => {
console.log(Date())
resolve(1)
}, 2000)
})
}
执行结果:
当然,异步并发控制有非常多的场景,有很多不同的、性能更好的解决方法,本文的方法只是作为一个参考。
如果大家有更好的思路或者对并发控制性能上有什么想法的话欢迎评论或者私信交流!