如何使用Promise.any()
Promise.any(promises) 是一个辅助函数,它可以并行地运行承诺,并从 列表中解析到第一个成功解析的承诺的值。promises
让我们看看Promise.any() 如何工作。
1.Promise.any()
Promise.any() 对于以并行和竞赛的方式执行独立的异步操作是很有用的,可以得到任何第一个被履行的承诺的值。
该函数接受一个数组(或一般是一个可迭代的)的承诺作为参数。
javascript
const anyPromise = Promise.any(promises);
当输入的promises 中的任何第一个承诺被实现时,anyPromise 会立即解析为该承诺的值。
你可以使用then-able 语法提取第一个承诺的值。
javascript
anyPromise.then(firstValue => { firstValue; // The value of the first fulfilled promise });
或使用async/await 语法。
javascript
const firstValue = await anyPromise; firstValue; // The value of the first fulfilled promise
由Promise.any() 返回的承诺与任何第一个被履行的承诺一起履行。即使有些承诺被拒绝,这些拒绝也会被忽略。
然而,如果输入数组中的所有承诺都被拒绝,或者输入数组是空的,那么Promise.any() ,以一个包含输入承诺的所有拒绝原因的聚合错误拒绝。
2.水果和蔬菜
在深入研究Promise.any() ,让我们定义2个简单的辅助函数。
首先,resolveTimeout(value, delay) - 返回一个承诺,在通过delay 的时间后与value 实现。
javascript
function resolveTimeout(value, delay) {
return new Promise(
resolve => setTimeout(() => resolve(value), delay)
);
}
第二,rejectTimeout(reason, delay) - 返回一个承诺,在通过delay 时间后用reason 拒绝。
javascript
function rejectTimeout(reason, delay) {
return new Promise(
(r, reject) => setTimeout(() => reject(reason), delay)
);
}
让我们用这些辅助函数在Promise.any() 上做实验。
2.1 所有承诺的实现
让我们尝试访问当地杂货店的第一个已解决的列表。
javascript
const statusesPromise = Promise.allSettled([
resolveTimeout(['potatoes', 'tomatoes'], 1000),
resolveTimeout(['oranges', 'apples'], 1000)
]);
// wait...
const statuses = await statusesPromise;
// after 1 second
console.log(statuses);
// [
// { status: 'fulfilled', value: ['potatoes', 'tomatoes'] },
// { status: 'fulfilled', value: ['oranges', 'apples'] }
// ]
Promise.any([...]) 返回一个 ,在1秒内解析到蔬菜列表 。所有这些都是因为蔬菜的承诺已经首先实现。promise ['potatoes', 'tomatoes']
第二个承诺,即水果列表,在2秒内解决,但其值被忽略了。
2.2 拒绝一个承诺
想象一下,在杂货店里已经没有蔬菜了。在这种情况下,让我们拒绝蔬菜的承诺。
Promise.any() 在这种情况下会如何工作?
const statusesPromise = Promise.allSettled([
resolveTimeout(['potatoes', 'tomatoes'], 1000),
rejectTimeout(new Error('Out of fruits!'), 1000)
]);
// wait...
const statuses = await statusesPromise;
// after 1 second
console.log(statuses);
// [
// { status: 'fulfilled', value: ['potatoes', 'tomatoes'] },
// { status: 'rejected', reason: Error('Out of fruits!') }
// ]
这种情况有点棘手。
首先,蔬菜的承诺在1秒后被拒绝。然而,Promise.any() ,跳过这个拒绝,仍然等待查看水果的承诺状态。
最后,又过了一秒钟,水果的承诺被解析为一个水果的列表['oranges', 'apples'] 。马上,由Promise.any([...]) 返回的承诺也解析为这个值。
2.3 拒绝所有承诺
如果杂货店里既没有蔬菜也没有水果怎么办?在这种情况下,两个承诺都被拒绝。
javascript
const statusesPromise = Promise.allSettled([
rejectTimeout(new Error('Out of vegetables!'), 1000),
rejectTimeout(new Error('Out of fruits!'), 1000)
]);
// wait...
const statuses = await statusesPromise;
// after 1 second
console.log(statuses);
// [
// { status: 'rejected', reason: Error('Out of vegetables!') },
// { status: 'rejected', reason: Error('Out of fruits!') }
// ]
所有输入的承诺都被拒绝。因此,由Promise.any([...]) 返回的承诺也会被拒绝,并带有一种特殊的错误--聚合错误(AggregateError),它包含输入承诺的拒绝原因。
聚合错误提供了一个特殊的属性errors :它是一个数组,包含被拒绝的输入承诺的错误。
3.3.结论
Promise.any() 对于以竞赛方式并行执行独立的异步操作,以获得任何第一个成功解决的承诺的值,是非常有用的。
如果Promise.any() 的所有输入承诺都被拒绝,那么由辅助函数返回的承诺也会被拒绝,并带有一个聚合错误,该错误包含了一个特殊属性中的输入承诺的拒绝原因:aggregateError.errors 。
请注意,如果输入数组为空,Promise.any([]) 也会被拒绝。
挑战:Promise.any() 和Promise.race() 的主要区别是什么?