不要乱用 Promise.all

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战

问题背景

在进行多个异步处理时,使用比较多的可能是 Promise.all。但是在使用 Promise.all 进行异步处理时发生了服务超时现象,是因为需要处理的异步太多导致的吗?还是业务处理出问题?

Promise.all

Promise.all(iterable) 返回值: Promise 实例

  • Array,Map,Set都属于ES6的iterable类型
  • 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)
  • 如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
 const promise1 = Promise.resolve(3);
    const promise2 = 11;
    const promise3 = new Promise((resolve, reject) => {
        setTimeout(resolve, 100, 'hi');
    });
​
    Promise.all([promise1, promise2, promise3]).then((values) => {
        console.log(values);
});
复制代码

执行以上代码时,输出结果:[ 3, 11, 'hi' ]

场景验证

场景1:多个promise 都正常resolve, 但 iterable 的数量不断增加,

let promiseAry = [];
let maxNum = 1000; // 控制 promise 对象数
for (var i = 0; i < maxNum; i++) {
   promiseAry.push(Promise.resolve(i))
}
console.time('test');
await Promise.all(promiseAry).then((values) => {
  console.log(values.length)
}).catch(error => {
  console.log(`error: ${error}`)
})
console.timeEnd('test');
复制代码

其中 maxNum 控制 promise 对象数,当我从100 不断增加到1000000时,直接报错:error: RangeError: Too many elements passed to Promise.all, 所以 Promise.all 可处理的异步有数量的限制。具体限制多少数量,可以查看 stackoverflow 上一个人的测试结果:详细地址.

场景2:异步数量允许范围内, 参数 iterable 设置为延时 2秒的Promise 对象

let promiseAry = [];
let maxNum = 1000; // 控制 promise 对象数
for (var i = 0; i < maxNum; i++) {
  promiseAry.push(new Promise((resolve, reject) => {
            setTimeout(resolve, 2000, 'hi'); // 延时 2s
   }));
}
console.time('test');
await Promise.all(promiseAry).then((values) => {
  console.log(values.length)
}).catch(error => {
  console.log(`error: ${error}`)
})
console.timeEnd('test');
复制代码

执行结果:无论异步数量多少个,其执行的时间基本都是一样的结果:test: 2.008s。因为时异步执行所有执行时间一样符合合理结果。

场景3:异步数量允许范围内, 参数 iterable 中存在一个延时 1天时间的 promise 对象

    let promiseAry = [];
    for (var i = 0; i < 100; i++) {
        if (i == 40) {
            promiseAry.push(new Promise((resolve, reject) => {
                setTimeout(resolve, 24 * 3600 * 1000, 'hi');
            }));
        } else {
            promiseAry.push(Promise.resolve(i))
        }
    }
    console.time('test');
    await Promise.all(promiseAry).then((values) => {
        console.log(values.length)
    }).catch(error => {
        console.log(`error: ${error}`)
    })
    console.timeEnd('test');
复制代码

将其中的的一个promise对象 ,延时一天,在执行的时候程序就会一直处于正在运行的状态。如果遇到这样情况的时候就会有很大的风险。多个异步处理时,其中出现一个超时,且没有进行超时情况处理的时候就会导致整个服务都无法使用,其他请求过来都会变成等待该超时的处理结束后才能执行。

结论

所以,如果使用 Promise.all,需要视情况分析然后进行使用:

  • 数据量比较大的慎用
  • 异步处理需要进行容错处理,超时处理,若无法判定超时,可不用 promise.all 方式进行异步处理
  • 因为promise.all 中多个异步有一个 reject,就会导致所有 Promise 回调执行都失败,所以建议 Promise.all使用在多个异步处理是强相关的业务逻辑里,比如场景:付款前需要先异步处理其他业务,只有几个业务都成功后才能执行付款操作。

猜你喜欢

转载自juejin.im/post/7067812443585511431