Promise
对象是ECMAScript 6中新增的对象,主要将 JavaScript 中的异步处理对象和处理规则进行了规范化。前面介绍了《Promise.any() 原理解析及使用指南》,本文来介绍另一个方法 Promise.all(promises)
,能够一次并行处理多个 promise
,并且只返回一个 promise
实例, 那个输入的所有 promise
的 resolve
回调的结果是一个数组。
下面来看看 Promise.all()
是如何工作的。
1.工作原理
Promise.all()
是一个内置的辅助函数,接受一组 promise
(或者一个可迭代的对象),并返回一个promise
:
const allPromise = Promise.all([promise1, promise2, ...]);
可以使用 then
方法提取第一个 promise
的值:
allPromise.then((values) => { values; // [valueOfPromise1, valueOfPromise2, ...] });
也可以使用 async/await
语法:
const values = await allPromise; console.log(values); // [valueOfPromise1, valueOfPromise2, ...]
Promise.all()
返回的 promise
被解析或拒绝的方式。
如果 allPromise
都被成功解析,那么 allPromise
将使用一个包含各个 promise
已执行完成后的值的数组作为结果。数组中 promise
的顺序是很重要的——将按照这个顺序得到已实现的值。
但是如果至少有一个 promise
被 rejected
,那么 allPromise
会以同样的原因立即 rejected
(不等待其他 promise
的执行)。
如果所有的 promise
被 rejected
,等待所有的promise
执行完成,但只会返回最先被rejected
的promise
的 reject
原因。
2. 使用指南
现在来深入介绍一下 Promise.all()
, 在这之前,先来定义 2 个简单的函数。
函数
resolveTimeout(value, delay)
将返回一个在经过delay
时间后有resolve
的promise
。
function resolveTimeout(value, delay) { return new Promise((resolve) => setTimeout(() => resolve(value), delay)); }
函数
rejectTimeout(reason, delay)
将返回一个在经过delay
时间后有reject
的promise
。
function rejectTimeout(reason, delay) { return new Promise((r, reject) => setTimeout(() => reject(reason), delay)); }
接下来使用上面定义的2个辅助函数来试试 Promise.all()
。
2.1 完成所有 promises
下面定义了一个 promise
数组 allPromise
,所有的 promise
都能够成功的 resolve
值,如下:
function resolveTimeout(value, delay) { return new Promise((resolve) => setTimeout(() => resolve(value), delay)); } const fruits = ["potatoes", "tomatoes"]; const vegetables = ["oranges", "apples"]; const allPromise = [ resolveTimeout(fruits, 2000), resolveTimeout(vegetables, 1000), ]; const promise = Promise.all(allPromise); // 等待... 2秒后 const list = async () => { try { const result = await promise; console.log(result); } catch (error) { console.log(error.errors); } }; list(); // [ [ 'potatoes', 'tomatoes' ], [ 'oranges', 'apples' ] ]
从上面执行的结果来看 Promise.all()
返回的 promise
的 resolve
数组是按照执行前 allPromise
的顺序组成其结果。
promise
数组的顺序直接影响结果的顺序,和promise
执行完成的先后无关。
2.2 一个 promise
被 rejected
将上面数组 allPromise
的第一个 promise
出现异常被 rejected
,如下代码:
const promise = Promise.all([ rejectTimeout(new Error("fruits is empty"), 5000), resolveTimeout(vegetables, 1000), ]); // 等待... const list = async () => { try { const result = await promise; console.log(result); } catch (error) { console.log(error); } }; list(); // Error: fruits is empty
然而,在经过 5秒
之后,第一个 promise
由于异常被 rejected
,使得 allPromise
也被 rejected
,并返回跟第一个 promise
一样的错误信息:Error: fruits is empty
,即使在 1秒
后就完成的第二个 promise
的值也不被采纳。
接下来将数组 allPromise
的所有 promise
都抛出异常被 rejected
,通过定时器将 rejected
的顺序做个调整,如下:
const promise = Promise.all([ rejectTimeout(new Error("fruits is empty"), 5000), rejectTimeout(new Error("vegetables is empty"), 1000), ]); // 等待... const list = async () => { try { const result = await promise; console.log(result); } catch (error) { console.log(error); } };
经过 5秒
之后完成执行,而结果显示为 Error: vegetables is empty
,不难看出 allPromise
被 rejected
的原因是最先 rejected
的promise
。
Promise.all()
的这种行为被称为快速失败,如果promise
数组中至少有一个promise
被rejected
,那么返回的promise
也被拒绝。如果promise
数组中所有的都被rejected
,那么返回的promise
被拒绝的原因是先rejected
的那一个。
总结
Promise.all()
是并行执行异步操作并获取所有 resolve
值的最佳方法,非常适合需要同时获取异步操作结果来进行下一步运算的场合。