Promise.all 并发限制

2020-07-07  本文已影响0人  Yong_bcf4

Promise.all 并发限制

简介

Promise.all 可以保证,promises 数组中所有 promise 对象都达到 resolve 状态,才执行 then 回调。 这时候考

虑一个场景:如果你的 promises 数组中每个对象都是 http 请求,或者说每个对象包含了复杂的调用处理。而

这样的对象有几十万个。 那么会出现的情况是,你在瞬间发出几十万 http 请求(tcp 连接数不足可能造成等

待),或者堆积了无数调用栈导致内存溢出。 这时候,我们就需要考虑对 Promise.all 做并发限制。

Promise.all 并发限制指的是,每个时刻并发执行的 promise 数量是固定的,最终的执行结果还是保持与原来的

Promise.all 一致。

现在已经有的成熟解决方案:tiny-async-pool、es6-promise-pool、p-limit

实现思路

主要是通过第三方插件,来控制异步函数的执行。

代码参考:tiny-async-pool 源码。相比于其主功能函数做了以下优化:

1、使用方式更接近原本的 Promise.all。

function promsie1() {}

function promsie2() {}

function promsie3() {}

Promise.all([promsie1(), promsie2(), promsie3()]);

PromiseLimit([promsie1, promsie2, promsie3]);

2、当执行过程中某个 promise 返回 reject 则停止后续的 promise 执行。

代码

function PromiseLimit(funcArray, limit = 5) {

let i = 0;

const result = [];

const executing = [];

const queue = function() {

if (i === funcArray.length) return Promise.all(executing);

const p = funcArray[i++]();

result.push(p);

const e = p.then(() => executing.splice(executing.indexOf(e), 1));

executing.push(e);

if (executing.length >= limit) {

return Promise.race(executing).then(

() => queue(),

e => Promise.reject(e)

);

}

return Promise.resolve().then(() => queue());

};

return queue().then(() => Promise.all(result));

}

效果演示

// 测试代码

const result = [];

for (let index = 0; index < 10; index++) {

result.push(function() {

return new Promise((resolve, reject) => {

console.log("开始" + index, new Date().toLocaleString());

setTimeout(() => {

resolve(index);

console.log("结束" + index, new Date().toLocaleString());

}, parseInt(Math.random() * 10000));

});

});

}

PromiseLimit(result).then(data => {

console.log(data);

});

// 修改测试代码 随机失败或者成功

const result = [];

for (let index = 0; index < 10; index++) {

result.push(function() {

return new Promise((resolve, reject) => {

console.log("开始" + index, new Date().toLocaleString());

setTimeout(() => {

if (Math.random() > 0.5) {

resolve(index);

} else {

reject(index);

}

console.log("结束" + index, new Date().toLocaleString());

}, parseInt(Math.random() * 1000));

});

});

}

PromiseLimit(result).then(

data => {

console.log("成功", data);

},

data => {

console.log("失败", data);

}

);

上一篇下一篇

猜你喜欢

热点阅读