使用 Promise.allSettled 解决 Promise.all 遇到一个错误就抛出所有 Promise 的问题

阅读时长 5 分钟读完

Promise 是 JavaScript 中异步编程的一种解决方案,它为异步操作提供了一种统一的、链式的处理方式。但在并发执行多个异步操作时,我们经常需要等待所有异步操作都完成后再进行处理,这时就需要使用 Promise.all。

Promise.all 接收一个 Promise 数组,返回一个新的 Promise,这个新 Promise 的状态是由所有 Promise 状态决定的。具体来说,只有所有 Promise 都成功 resolved,新 Promise 才会成功 resolved,否则只要有一个 Promise rejected,新 Promise 就会失败 rejected,并返回失败的 Promise 的错误原因。

这种机制非常方便,但也存在一个弊端:如果 Promise 数组中的某个 Promise 出现错误而被 rejected,Promise.all 就会立即终止执行并返回失败原因,导致其他 Promise 没有机会执行。这种行为不仅影响效率,而且也很难 debug 错误,因为我们无法得知是哪个 Promise 出错了,需要逐个排查。

例如,假设我们有一些并行的异步任务需要执行,如下所示:

-- -------------------- ---- -------
----- -------- - -
  ---------------------------------------------
  -------------------------------------------------------
  ---------------------------------------------------
--

---------------------
  ----------------- -------------- ----------- -- --------------------- -------------- -----------
  ------------ -- ----------------------

如果其中任意一个 API 请求失败,整个 Promise 数组就会返回一个错误,Promise.all 就会抛出失败原因并停止执行。这时,我们无法知道是哪个 API 请求出现了错误。

为了解决这个问题,ES2020 引入了 Promise.allSettled 方法。

Promise.allSettled

Promise.allSettled 方法与 Promise.all 很相似,它也接收一个 Promise 数组作为参数,并返回一个新的 Promise,但新 Promise 只有在所有 Promise 都状态发生变化后才会被 resolved,不会被 rejected。

新 Promise 的值是一个数组,包含了所有 Promise 的状态信息,每个状态有以下属性:

  • status:字符串,Promise 的状态,可能的值为 fulfilled(成功)或 rejected(失败)
  • valuereason:对应的值或错误原因,分别对应相应 Promise 的 resolvereject 时传入的参数

这意味着,即使有一个或多个 Promise 被 rejected,Promise.allSettled 仍会等待所有 Promise 执行完毕再返回结果,不会在出现错误时终止执行。

改写上面的例子,使用 Promise.allSettled 来获取所有 API 请求的结果集合:

-- -------------------- ---- -------
----- -------- - -
  ---------------------------------------------
  -------------------------------------------------------
  ---------------------------------------------------
--

----------------------------------------- -- -
  ----- ---------- -------------- ---------- - -------------- ------- ------ ------ -- -- -
    -- ------- --- ------------ -
      ------ ------
    - ---- -
      ------------------ -- --- -------- --------- --------
      ------ -----
    -
  ---
  
  --------------------- -------------- -----------
---

在 Promise.allSettled 的回调函数中,我们遍历每个 Promise 的状态结果,对于 fulfilled 状态的 Promise,把它的值保存到对应的变量中,如果是 rejected 状态的 Promise,打印错误,但不再抛出整个 Promise。

总结

Promise.allSettled 解决了 Promise.all 某个 Promise 出错导致整个 Promise 都抛错的问题,它能够等待所有 Promise 执行完毕后统一返回结果,不受中途失败的 Promise 影响。

但需要注意的是,Promise.allSettled 返回的结果集合中,既包含成功的 Promise 的值,也包含失败的 Promise 的原因,因此在使用结果集合时,需要对状态进行判断,以避免使用失败的 Promise 的值或误判成功结果。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64b26ba648841e9894ea51fe

纠错
反馈