ECMAScript 2020 中 Promise.all 方法可能出现的重复调用问题及解决方法

阅读时长 6 分钟读完

在前端开发中,Promise.all 方法是一个非常常用的函数,它可以将多个 Promise 对象组合成一个 Promise 对象。当所有 Promise 对象都成功完成时,Promise.all 的返回值会依次包含所有 Promise 返回值组成的数组;如果有任意一个 Promise 失败或抛出异常,则 Promise.all 返回的 Promise 也会立即失败。由于 Promise.all 的实现方式,我们可能会遇到重复调用的问题,本文将详细介绍这个问题和解决方法。

问题描述

在 ECMAScript 2020 中,Promise.all 方法的行为和之前版本基本相同,但是在使用 Promise.all 处理多个 Promise 时,如果其中一个 Promise 发生错误或被拒绝 (rejected),而其他 Promise 尚未完成,此时可以进行重试。然而,如果使用 Promise.all 进行重试,可能会导致其内部的 Promise 对象被重复调用,从而导致代码逻辑出现问题。

下面是一个示例,展示如何使用 Promise.all 实现 HTTP 请求:

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

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

这段代码使用了 fetch 函数发送 HTTP 请求,并将返回的 Promise 对象存入了数组 promises 中。然后,程序使用 Promise.all 来等待所有请求完成,并将每个请求的响应结果输出到控制台上。与此类似,我们可以使用 Promise.all 来处理任何形式的异步操作。

问题分析

假设我们现在启动了一个 HTTP 请求,但由于某种原因,这个请求被挂起了,而我们又再次调用了该请求,此时问题就出现了。在这种情况下,Promise.all 内部的两个 Promise 对象实际上是相同的,因此当其中一个 Promise 被完成时,另一个 Promise 也会被完成。

这意味着,Promise.all 的 then 方法将在两次调用后立即执行,而不是在所有请求完成后执行。在上面的示例中,如果我们遇到类似的情况,会看到两次相同的输出,这可不是我们想要的结果。

因此,我们需要找到一种解决方案,以在重试 Promise.all 方法时避免重复调用 Promise 对象,这将有助于确保代码逻辑的正确性。

解决方案

为了解决 Promise.all 的重复调用问题,可以通过以下方式之一进行更改:

  1. 缓存 Promise.all 内部的 Promise 对象,以便在出现重复调用时能够避免重复使用这些 Promise 对象。
-- -------------------- ---- -------
--- ---- - ---------------------- --------------------- ----------------------

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

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

在这个函数中,我们将 fetch 请求封装在一个函数内,并将 Promise.all 的结果返回。这样,如果我们需要重复调用该函数来重新发送请求,我们可以确保每次都会获取新的 Promise 对象,从而避免重复调用。

  1. 通过使用 Promise.race 方法,我们可以在指定的时间内等待 Promise 对象完成。如果一个 Promise 对象在指定的时间内未完成,则可以执行一个备用逻辑,或者再次发送请求。
-- -------------------- ---- -------
--- ---- - ---------------------- --------------------- ----------------------

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

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

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

在这个函数中,我们使用了 Promise.race 方法来同时等待 HTTP 请求完成和超时。如果请求成功返回,Promise.race 的返回值就是请求的 Promise 对象,这样我们就可以将该 Promise 传递给 Promise.all。如果请求超时,Promise.race 的返回值将变成一个拒绝 (rejected) 状态的 Promise 对象,这样我们就可以进行备用逻辑或再次发送请求。

总结

Promise.all 是一个非常有用的函数,它可以将多个 Promise 对象组合成一个 Promise 对象。但是,由于其内部的实现方式,我们有可能会遇到重复调用的问题。本文介绍了这个问题和解决方法,我们可以选择缓存 Promise.all 内部的 Promise 对象,或通过使用 Promise.race 方法来等待 HTTP 请求完成并处理超时情况。这些技巧都有助于我们确保代码逻辑的正确性,并提高代码复用的效率。

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

纠错
反馈