ECMAScript 提案:Promise.any()
由 Mathias Bynens, Kevin Gibbons 和 Sergey Rubanov 提出的 ECMAScript 提案 “promise.any()” 为 JavaScript 提出一个新的 Promise 方法。这边博客文章解释它如何工作。
背景知识
下面有两个有利于理解这篇文章的背景知识资源:
- 博客文章 “JavaScript Promise combinators: .all(), .race(), .allSettled()”
- “JavaScript for impatient programmers” 的章节 “Promises for asynchronous programming”
Promise.any()
promise.any()
的类型签名是:
Promise.any<T>(promises: Iterable<Promise<T>>): Promise<T>
Promise.any()
返回一个 Promise p
。它的结果取决于参数 promises
(迭代 Promises 的结果引用):
- 如果有一个 Promise 的状态为成功(fulfilled),
p
的状态为成功(resolved)。 - 如果所有的 Promises 都失败,
p
的状态将失败(rejected),结果值是包含所有失败状态的AggregateError
的实例的结果集。
AggregateError
的类型签名是(删除了一些成员):
class AggregateError {
constructor(errors: Iterable<any>, message: string)
get errors(): Array<any>
get message(): string
}
下面的插图说明了 Promise.any()
如何工作:
现在展示一个 Promise 成功时发生了什么:
const promises = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.resolve('result'),
]
Promise.any(promises)
.then(result => assert.equal(
result,
'result'
))
现在展示一个 Promise 失败时发生了什么:
const promises = [
Promise.reject('ERROR A'),
Promise.reject('ERROR B'),
Promise.reject('ERROR C'),
]
Promise.any(promises)
.catch(aggregateError => assert.deepEqual(
aggregateError.errors,
['ERROR A', 'ERROR B', 'ERROR C']
))
Promise.any() 与 Promise.all() 对比
有两个方法对比 Promise.any()
和 Promise.all()
:
- 它们彼此相反:
Promise.all()
: 第一个输入拒绝将拒绝结果 Promise 或它的实现值是一个具有输入实现值的数组。Promise.any()
: 第一个输入实现满足结果 Promise 或它的拒绝值是一个带有输入拒绝值的数组。
- 有不同的重点:
Promise.all()
对所有成功感兴趣。相反的情况(至少一个拒绝)导致拒绝。Promise.any()
对第一个实现很感兴趣。相反的情况(仅拒绝)导致拒绝。
Promise.any() 与 Promise.race() 对比
Promise.any()
和 Promise.race()
也可以联系起来,但有趣的是它们的不同:
Promise.race()
对完成感兴趣。首先完成的 Promise 是“胜利”。换句话说:我们想知道首先完成的异步计算。Promise.any()
对成功感兴趣。首先成功的 Promise 是“胜利”。换句话说:我们想知道首先成功的异步计算。
主要(相对罕见)的用例 .race()
是超时 Promises。.any()
的用例范围更广。接下来,我们来看它们。
Promise.any() 的用例
如果我们有多个异步计算,同时仅仅对第一个成功的感兴趣,就可以使用 Promise.any()
。在某种程度上,我们让计算彼此竞争,并使用最快的一个
以下代码演示了下载资源时的展示:
const resource = await Promise.any([
fetch('https://example.com/first.txt')
.then(response => response.text()),
fetch('https://example.com/second.txt')
.then(response => response.text()),
])
我们可以使用相同的模式来使用更快下载的模块:
const lodash = await Promise.any([
import('https://primary.example.com/lodash'),
import('https://secondary.example.com/lodash'),
])
作为比较,下面的代码展示我们在主服务器出错时使用备份的第二服务器:
let lodash
try {
lodash = await import('https://primary.example.com/lodash')
} catch {
lodash = await import('https://secondary.example.com/lodash')
}
如何实施 Promise.any()?
简单的实现 Promise.any()
基本上是的类似 Promise.all()
的镜像版本。在 Promise 的博客文章中查看代码,以获取更多信息。
使用 Promise.any()
- npm 包 promise.any 提供一个填充。
- 针对其它实现,请考虑功能提案。
本文由 吳文俊 翻译,原文地址:ES2021: Promise.any()。