如何在 Promise 中实现超时控制

阅读时长 7 分钟读完

在前端开发中,我们经常会遇到一些需要等待异步操作完成的场景,如发送请求、加载图片等。在这些场景中,我们通常会使用 Promise 来管理异步操作,但是有时候异步操作可能会因为网络问题等原因导致一直没有响应,这时候我们就需要在 Promise 中实现超时控制来避免程序一直等待下去。

Promise 基础知识

在深入探讨如何实现超时控制之前,我们需要先了解一些 Promise 的基础知识。

Promise 的基本用法

Promise 是 JavaScript 中一种用于管理异步操作的对象,它可以将异步操作转化为同步的方式进行处理。Promise 有三种状态:pendingfulfilledrejected。当异步操作成功时,Promise 的状态会从 pending 转变为 fulfilled,并且会传递一个结果值;当异步操作失败时,Promise 的状态会从 pending 转变为 rejected,并且会传递一个错误对象。

下面是一个基本的 Promise 示例:

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

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

在这个示例中,我们通过 new Promise() 创建了一个 Promise 对象,传入了一个函数作为参数。这个函数中模拟了一个异步操作,1 秒后随机返回一个成功或失败的结果。当异步操作成功时,我们调用 resolve() 方法并传入一个参数,表示异步操作的结果;当异步操作失败时,我们调用 reject() 方法并传入一个错误对象,表示异步操作的失败原因。

然后我们使用 promise.then() 方法来监听 Promise 的状态变化。当 Promise 的状态变为 fulfilled 时,then() 方法会被调用并传递异步操作的结果;当 Promise 的状态变为 rejected 时,catch() 方法会被调用并传递错误对象。

Promise 的链式调用

除了基本用法之外,Promise 还支持链式调用。在链式调用中,每个 Promise 对象都可以返回一个新的 Promise 对象,从而实现多个异步操作的串联。

下面是一个简单的示例:

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

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

在这个示例中,我们首先创建了一个 Promise 对象,并在 1 秒后调用 resolve() 方法传递了一个字符串。然后我们使用 then() 方法来监听 Promise 的状态变化,并返回一个新的 Promise 对象。在新的 Promise 对象中,我们同样使用 setTimeout() 来模拟一个异步操作,并在 1 秒后调用 resolve() 方法传递另一个字符串。最后我们再次使用 then() 方法来监听 Promise 的状态变化,并输出传递的字符串。

如何实现超时控制

在了解了 Promise 的基础知识之后,我们可以开始探讨如何在 Promise 中实现超时控制了。

方案一:使用 Promise.race()

最简单的实现方式是使用 Promise.race() 方法。Promise.race() 方法接收一个 Promise 数组作为参数,并返回一个新的 Promise 对象。这个新的 Promise 对象将会在参数数组中的任意一个 Promise 对象状态变为 fulfilledrejected 时,立即变为对应状态,并返回相应的结果值或错误对象。

我们可以利用这个特性,在 Promise 中添加一个超时检测 Promise 对象,当超时检测 Promise 对象先于异步操作的 Promise 对象状态变化时,即可判定异步操作超时。

下面是一个示例:

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

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

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

在这个示例中,我们定义了一个 timeoutPromise() 函数,它接收一个 Promise 对象和一个超时时间作为参数。在函数内部,我们使用 Promise.race() 方法来创建一个新的 Promise 对象,并将参数中的 Promise 对象和一个超时检测 Promise 对象作为参数传入。超时检测 Promise 对象会在指定的超时时间后调用 reject() 方法并传递一个错误对象。

然后我们使用 timeoutPromise() 函数来包装一个异步操作的 Promise 对象,并设置一个较短的超时时间。当异步操作的 Promise 对象状态变化时,timeoutPromise() 函数返回的 Promise 对象也会相应地变为对应状态,并返回相应的结果值或错误对象。

方案二:使用 Promise 和 setTimeout()

除了使用 Promise.race() 方法之外,我们还可以使用 Promise 和 setTimeout() 方法来手动实现超时控制。

下面是一个示例:

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

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

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

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

在这个示例中,我们同样定义了一个 timeoutPromise() 函数,并在函数内部创建了一个超时检测 Promise 对象。然后我们使用 Promise.race() 方法将异步操作的 Promise 对象和超时检测 Promise 对象作为参数传入,并在返回的 Promise 对象中使用 finally() 方法来清除超时计时器。

总结

在本文中,我们介绍了 Promise 的基本用法和链式调用,并讨论了如何在 Promise 中实现超时控制。我们提出了两种实现方案,分别是使用 Promise.race() 方法和手动使用 Promise 和 setTimeout() 方法。这些方案都可以帮助我们在异步操作中实现超时控制,避免程序一直等待下去。

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

纠错
反馈