type
Post
status
Published
date
Jul 2, 2022
slug
nodejs-promise-all-all-settled
summary
最近工作中需要使用 Promise 处理多个异步操作,对于 Promise.all 和 Promise.allSettled 的使用场景和方法有些不明确,遂有此文
tags
开发
Nodejs
JavaScript
category
技术分享
icon
password
当我们需要在 JavaScript 中处理多个异步操作时,Promise.all 和 Promise.allSettled 是两个非常有用的方法。虽然它们都可以协调多个 Promise 并等待它们全部完成,但它们之间还存在一些明显的区别
Promise.all 和 Promise.allSettled 的区别
Promise.all()
Promise.all
方法会接收一个由多个 Promise 对象组成的数组,并返回一个新的 Promise 对象,该 Promise 对象将在所有 Promise 对象都成功解决后才会被解决,并返回所有 Promise 对象的结果数组。如果任何一个 Promise 对象被拒绝,则该 Promise.all 实例将立即被拒绝,并返回第一个被拒绝的 Promise 对象的原因。下面是一个使用 Promise.all 的示例:
const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]).then(values => { console.log(values); // [3, 42, "foo"] });
如果我们仔细观察 Promise.all 的源码实现,可以发现它的实现非常简单:
Promise.all = function (promises) { return new Promise(function (resolve, reject) { var results = []; var count = promises.length; var index = 0; promises.forEach(function (promise, i) { Promise.resolve(promise).then(function (value) { results[i] = value; index++; if (index === count) { resolve(results); } }).catch(function (err) { reject(err); }); }); }); };
该方法首先创建了一个空数组
results
来存储 Promise 的解决值,然后遍历传入的 Promise 数组,依次对每个 Promise 对象调用Promise.resolve()
,将其转换成 Promise 实例并执行。在每个 Promise 实例的
then()
方法中,将值存储到 results
数组中,同时检查是否所有 Promise 都已经解决,如果是,则调用 resolve()
,并返回结果数组 results
;否则,如果有任何 Promise 被拒绝,则直接调用 reject()
并返回拒绝的原因。Promise.allSettled()
Promise.allSettled
方法与 Promise.all 类似,也接收一个 Promise 对象数组,并且返回一个新的 Promise 对象。但不同的是,当所有 Promise 都成功或失败解决时,返回的 Promise 对象始终会被成功解决,其结果是一个对象数组,每个对象都包含 Promise 的状态(fulfilled 或 rejected)与值/原因。下面是一个使用 Promise.allSettled 的示例:
const promise1 = Promise.resolve(3); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Something went wrong')); const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'foo')); Promise.allSettled([promise1, promise2, promise3]).then(results => { console.log(results); /* [ {status: "fulfilled", value: 3}, {status: "rejected", reason: "Something went wrong"}, {status: "fulfilled", value: "foo"} ] */ });
如果我们仔细观察 Promise.allSettled 的源码实现,可以发现它同样很简单:
Promise.allSettled = function (promises) { return new Promise(function (resolve) { var results = []; var count = promises.length; var index = 0; promises.forEach(function (promise, i) { Promise.resolve(promise).then(function (value) { results[i] = { status: 'fulfilled', value: value }; }, function (reason) { results[i] = { status: 'rejected', reason: reason }; }).finally(function () { index++; if (index === count) { resolve(results); } }); }); }); };
该方法首先创建了一个空数组
results
来存储 Promise 的状态和解决值/原因,然后遍历传入的 Promise 数组,依次对每个 Promise 对象调用Promise.all 和 Promise.allSettled 的使用场景
在实际开发中,如果我们需要等待
所有 Promise
都解决后再继续执行后续操作,可以使用 Promise.all 方法。例如,当我们需要从多个服务器获取数据并将其合并时,我们可以使用 Promise.all 来等待所有服务器返回数据后再进行下一步操作。此外,Promise.all 也适用于以下情况:
- 需要按照特定顺序完成多个异步操作;
- 需要同时解决多个异步操作;
- 需要处理所有 Promise 返回值的情况。
与之相比,Promise.allSettled 更适用于我们只关心
每个 Promise 的最终状态
(已解决或被拒绝)而不关心它们的解决值/原因
的情况。例如,当我们需要确保所有请求已经完成,但不需要处理每个请求的响应时,就可以使用 Promise.allSettled。此外,Promise.allSettled 还适用于以下情况:
- 必须处理所有 Promise 对象的状态信息的情况;
- 必须等待所有异步操作完成,无论它们是否成功;
- 需要缩短调试时间,以更快地了解每个异步操作的最终状态。
需要注意的地方
在使用 Promise.all 和 Promise.allSettled 时需要注意以下几点:
- 处理大量的 Promise 对象时,需要确保控制台不会因为输出过多信息导致崩溃;
- 在使用 Promise.all 时,需要确保传入的 Promise 数组中没有任何一个被拒绝,否则会
立即返回
第一个被拒绝的 Promise 的错误信息;
- 在使用 Promise.allSettled 时,需要注意其返回结果数组中包含每个 Promise 对象的
状态和值/原因
,需要根据实际情况来进行处理;
- 如果 Promise.all 或 Promise.allSettled 中传入的数组是空的,则会立即返回一个成功解决的 Promise,但它们都不会返回任何结果;
- 在处理 Promise.all 或 Promise.allSettled 的返回结果时,需要注意对代码做好错误处理,以避免未处理的异常情况。
- 作者:Evans
- 链接:https://evansblog.vercel.app//article/nodejs-promise-all-all-settled
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章