如何让 Promise.race() 正确处理多次调用?

引言

Promise 是 JavaScript 中异步编程的一种方式,它有很多的静态方法,其中之一就是 Promise.race()。Promise.race() 接受一个可迭代对象,返回一个新的 Promise 对象,该对象在第一个解决或拒绝的 Promise 时解决或拒绝。

但是,当多次调用 Promise.race() 时,它可能不会像我们想象的那样运行。本文将介绍多次调用 Promise.race() 的情况,并提供一些解决方案。

多次调用 Promise.race() 的问题

当我们多次调用 Promise.race() 时,只有第一个完成的 Promise 才会被解决或拒绝。其余 Promise 将被忽略,这可能不是我们想要的结果。

让我们看一下以下示例代码:

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

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

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

这个代码片段中我们先定义了一个 Promise.race(),让它在 0.5s 后解决为 'A'、在 1s 后解决为 'B'、在 1.5s 后解决为 'C'。然后,我们在 setTimeout() 中异步调用另一个 Promise.race(),让它在 0.1s 后解决为 'D'、在 0.4s 后拒绝为 'E'、在 0.6s 后解决为 'F'。

当我们运行代码时,输出结果为:

-

可以看到,'D'、'E' 和 'F' 的状态都被忽略了。这不是我们想要的结果,我们需要让每个 Promise 都被正确处理。

解决方案

有多种解决方案可以解决这个问题。

1. 将 Promise.race() 封装为类

我们可以封装一个类来处理多次调用 Promise.race() 的问题。

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

我们在这个类中封装了 Promise.race()。当第一个 Promise 完成时,我们通过判断 this.done 的值是否为 true 来判断该 Promise 是否已经被处理。如果是,则使用新创建的 Promise 对象。否则,我们将在当前对象上调用 then() 或 catch()。

可以看到,在上面的示例代码中,我们只需将 Promise.race() 替换为 Race 就可以了。

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

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

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

当我们运行代码时,输出结果为:

-
-

可以看到,我们现在正确处理了所有的 Promise。

2. 使用 Promise.all()

另一个解决方案是使用 Promise.all()。Promise.all() 接受一个可迭代对象,返回一个新的 Promise 对象,该对象在所有 Promise 都解决后解决。因为 Promise.all() 返回的 Promise 对象当所有 Promise 都已完成时才会完成,所以可以确保所有 Promise 都被处理。

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

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

当我们运行代码时,输出结果为:

----- ----

可以看到,我们成功处理了所有的 Promise。

结论

当我们多次调用 Promise.race() 时,只有第一个完成的 Promise 才会被解决或拒绝。其余 Promise 将被忽略,这可能不是我们想要的结果。我们可以封装一个类来解决这个问题,也可以使用 Promise.all()。相信读者已经了解多次调用 Promise.race() 的问题及其解决方案,可以在自己的项目中应用它们。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6705fc82d91dce0dc8566d9a