介绍
Promise.any
是 ES11 新增的 Promise 方法,它接收一个可迭代对象,返回一个 Promise 对象。当该可迭代对象中的任意一个 Promise 状态变为 fulfilled 时,返回的 Promise 对象状态变为 fulfilled。如果可迭代对象中的所有 Promise 都变为 rejected,返回的 Promise 对象状态变为 rejected,并返回所有 Promise 的 rejection 原因。
这个新的 Promise.any 方法很适合在处理多个异步操作时使用。
用途
在之前,为了实现“某个异步操作完成”这个需求,可以通过以下两种方式来达到目的:
- 通过
Promise.race
来达到目的。例如:
Promise.race([ fetch('https://api.example.com/data1'), fetch('https://api.example.com/data2') ]).then(data => console.log(data))
以上代码会返回先请求成功的数据,如果其中一个请求失败,将调用函数的 catch
方法。
但是,这种方式只返回第一个 resolved / fulfilled 的 Promise,如果你需要在多个异步操作中找到唯一的解决方法,那么 .race()
可能不是最好的选择。
- 对
Promise.all
的使用进行修改。例如:
Promise.all([ fetch('https://api.example.com/data1').catch(() => null), fetch('https://api.example.com/data2').catch(() => null) ]).then(([data1, data2]) => { const data = data1 || data2; console.log(data) })
这种方式, 如果其中一个 Promise 被拒绝 (rejected) 而且没有被 Catch 处理, 则 Promise.all
将会被拒绝并且传送第一个 promise 的拒绝原因。因此,由于我们在 .catch (() => null)
方案中处理了所有拒绝,所以数据不会丢失在某些情况下。
这种方法的缺点是,虽然它允许我们列出所有需要解决的 promise 的聚合起来,但在所有 promise 解决之前,我们需要空的数组或 null 作为我们传递到 Promise.all
中的项,在最后收集所有数据时也需要更多的工作。这样做似乎很麻烦,特别是对于更动态的任务集合和反应性增强程序而言。
现在,你可以使用 Promise.any
来解决这个问题,而不必担心毫无成果的模糊查询。
示例
看一个例子,我们假设我们有一个异步任务列表,我们想要在它们中找出第一个完成的异步任务的结果。
const promises = [ fetch("https://api.example.com/data1"), fetch("https://api.example.com/data2"), fetch("https://api.example.com/data3"), ]; Promise.any(promises).then((result) => console.log(result));
在将 Promise 列表作为参数传递给 Promise 之后,通过一个 .then()
块来接收 Promise 的解决方法。传入的第一个解决 Promise 的值将是我们唯一需要的数据,而不是整个 Promise 数组的解决数据。
案例
下面再看一下一个更复杂的情况,我们有很多服务提供商,我们想尝试从其中一个提供商中获取数据,如果其中一个请求成功,我们将使用提供此数据的服务提供商,如果所有尝试都失败了,我们将使用备用服务提供商。
-- -------------------- ---- ------- ----- ---------------- - - --------------------------- --------------------------- --------------------------- -- ----- -------------- - ----------------------------- ----- ------------ - ----- ----------- ---------- -- - ----- -------- - ------------------------ -- ------------------------------------------------- -- ----------- - --------------- - ----------------------------------- - -- --- - ----- ------ - ----- ---------------------- ------ - ------- ---------- ------ -- - ----- --- - ------ - ------- --------- -- - -- ------------------------------ ------------ -------- ------- ------ -- -- - -- ------- --- ---------- - -------------------- - ---- -- ------- --- ---------- - ------------------- ------ ----------- ------ ------------------------------ ------------- - -- -------- ------- ------ -- -- - -- ------- --- ---------- - -------------------- - ---- -- ------- --- ---------- - --------------- ---- --------- - ---
在此示例中, tryProviders()
函数接收一个服务提供商数组和一个目标 URL。尝试从提供者列表中的每个提供者获取数据,如果有一个提供者成功了,返回成功响应数据。否则,如果所有提供商都没有成功,返回失败响应,尝试备份提供商。
随着我们在 tryProviders()
函数中使用 fetch()
开始异步请求,我们通过 .map()
来创建一个 promise 列表。我们还使用 .then()
,使每个 promise 在解决之前将结果转换为 JSON。如果解决结果为 true,我们将结果值传递到后续内容。如果解决结果为错误,则我们使用 Promise.reject()
明确拒绝这个 promise。
上面的代码是一个相对高级的示例,但它说明了如果您的实际问题需要, Promise.any
可以在代替 .race() 或提供多个解决方法上更适用。
总结
ES11 中的 Promise.any 是一个非常有用的新功能。通过这个方法,我们只需要等待一组任务请求的最后结果是否成功或失败,然后我们就可以决定下一步要做什么。
除了更改 .all()
或 .race()
代码之外,计划在现有代码中使用 Promise.any()
不会太困难,因为工作方式与现有 Promise 模式相同,并且新的 Promise 的状态仅与其一组 Promise 中的第一个解决起决定作用。
有了 Promise.any,就可以根据我们的需求来选择一组 Promise 提供的所有服务商中的一个,而无需担心 undetermined results 的可能性, 让我们处理来自多个提供者的数据。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64530750968c7c53b077ab0f