[译]如何使用Promise.any()
翻译的一些说明:
Promise是一个状态机,有三种状态
- Pending 进行中
- Fulfilled resolve之后进行这种状态
- Rejected reject之后进入这种状态
状态变迁流程如下:

译文中会把Fulfilled翻译为完成,把Rejected翻译为被拒绝
Promise.any(promises)是一个帮助函数,用于并行执行多个promise请求并返回第一个成功resolve的promise的值。
让我们看一下Promise.any() 是如何工作的
1. Promise.any()
Promise.any()对于以并行和竞赛的方式执行独立的异步操作是很有用的,可以获得任何第一个完成(fulfilled)的promise的值。
该函数接受一个promise列表(或者是可迭代对象)作为参数
const anyPromise = Promise.any(promises);
当promise列表中的任何一个promise完成时,anyPromise就会立即resolve为该promise的值。
你可以使用then语法获取第一个promise的值
anyPromise.then(firstValue => {
firstValue; // 第一个fullfilled的promise的值
});
或者使用 async/await :
const firstValue = await anyPromise;
firstValue; // 第一个fullfilled的promise的值
Promise.any()返回的promise与第一个完成请求的promise一起完成(fulfilled),即便是有的promise请求失败了(rejected)也会被忽略。
如果所有的promise都失败了或者输入的promise数组为空,Promise.any() 会被拒绝(reject)并抛出一个aggregate error,错误中包含所有的promise请求的错误信息。
- 举个栗子-Fruits and vegetables
在使用Promise.any()之前,让我们定义两个帮助函数。
第一个, resolveTimeout(value, delay)——在delay毫秒之后返回一个fulfilled的promise,把传递的value参数作为resolve的参数。
function resolveTimeout(value, delay) {
return new Promise(
resolve => setTimeout(() => resolve(value), delay)
);
}
第二个, rejectTimeout(reason, delay) —在delay毫秒之后返回一个被reject的promise,并把参数reason作为错误信息填入。
function rejectTimeout(reason, delay) {
return new Promise(
(r, reject) => setTimeout(() => reject(reason), delay)
);
}
让我们使用这些帮助函数来测试下 Promise.any()。
2.1所有的promise都 fulfilled
例子:从商店中获取购买的清单:
const promise = Promise.any([
resolveTimeout(['potatoes', 'tomatoes'], 1000), resolveTimeout(['oranges', 'apples'], 2000)]);
// wait...
const list = await promise;
// after 1 second
console.log(list); // logs ['potatoes', 'tomatoes']
Promise.any([...]) 在1秒之后返回蔬菜列表['potatoes', 'tomatoes'],原因是这个promise首先完成(fulfilled)。
第二个promise在2秒之后完成,但是它的值会被忽略。
2.2 一个Promise被拒绝
想象一个场景:商店中没有蔬菜(vegetables),vegetables的promise就会被拒绝,这种情况下Promise.any()会怎么返回呢?
const promise = Promise.any([
rejectTimeout(new Error("Out of vegetables!"), 1000), resolveTimeout(["oranges", "apples"], 2000)
]);
// wait...
const list = await promise;
// after 2 seconds
console.log(list); // logs ['oranges', 'apples']
这种情况有点棘手。
首先, vegetables promise 在1秒后被拒绝。但是在这种情况下, Promise.any()会跳过这个promise并继续等待下一个promise的结果。
最终,2秒之后, fruits promise完成并返回对应的值 ['oranges', 'apples']。返回的值同样也是Promise.any([...])被resolve时得到的值。
2.3 所有的 promises 都被拒绝
如果商店中蔬菜和水果都没有,即这两个promise都被拒绝的场景,会发生什么?
const promise = Promise.any([
rejectTimeout(new Error('Out of vegetables!'), 1000), rejectTimeout(new Error('Out of fruits!'), 2000)]);
try {
// wait...
const list = await promise;
} catch (aggregateError) {
console.log(aggregateError); // logs AggregateError
console.log(aggregateError.errors);
// logs [Error('Out of vegetables!'), Error('Out of fruits!')]
}
所有输入的promise都被拒绝, Promise.any([...])返回的promise也会被拒绝,同时抛出一个特殊的错误——AggregateError ,错误中包含了所有promise被拒绝的原因。
aggregate error提供了一个特殊的属性errors:这是一个数组,包含了被拒绝的输入promise的错误。
- 总结
Promise.any()对于以并行和竞赛的方式执行独立的异步操作是很有用的,可以获得第一个resolved的promise的值。
如果所有输入的promise都被拒绝, Promise.any([...])返回的promise也会被拒绝,同时抛出一个特殊的错误—— aggregate error,它提供了一个属性aggregateError.errors,其中包含了所有输入promise被拒绝的原因。
注意,如果输入的列表为空, Promise.any([])也会被拒绝。
挑战:Promise.any()和Promise.race()之间的主要区别是什么?