使用 TypeScript 实现自定义 JavaScript Promise

阅读时长 11 分钟读完

JavaScript Promise 是异步编程中常用的编程模式,它可以帮助我们优雅地解决异步回调地狱的问题。虽然 Promise 已经被广泛应用,但是它并不是万能的,有些场景下我们需要自定义 Promise,本文将介绍如何使用 TypeScript 实现自定义 JavaScript Promise。

Promise

为了更好地理解自定义 Promise 的实现过程,我们先来了解一下 Promise 的概念和基本用法。

Promise 是一种包装异步操作并获取操作结果的方式,它提供了三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。当 Promise 转为 fulfilled 或 rejected 状态时,将会调用相应的回调函数。

下面是一个简单的 Promise 示例,它表示获取一个名字并打印出来:

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

在上述代码中,我们创建了一个 Promise 对象,在 1 秒后返回一个名字,利用 then() 方法获取名字并输出,如果发生错误则利用 catch() 方法处理错误。

实现自定义 Promise

为了实现自定义 Promise,我们需要完全理解 Promise 的三种状态和相应的回调函数,并且需要保证 Promise 符合 Promises/A+ 规范。本文中,我们将基于 TypeScript 来实现自定义 Promise。

TypeScript 类

在 TypeScript 中,我们可以使用类来实现自定义 Promise。我们需要定义一个 Promise 类,它需要有 resolve() 和 reject() 方法,并且需要一个 then() 方法来添加回调函数。

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

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

在上述代码中,我们定义了一个泛型 CustomPromise 类,它包含了 Promise 的三种状态:pending、fulfilled 和 rejected。value 和 reason 分别代表 Promise 的返回值和错误信息。onFulfilledCallbacks 和 onRejectedCallbacks 是回调函数,当 Promise 状态转为 fulfilled 或 rejected 时,将会执行回调函数。resolve() 和 reject() 方法分别用于将 Promise 状态设置为 fulfilled 或 rejected,then() 方法用于添加回调函数。

resolve() 方法

resolve() 方法用于将 Promise 状态设置为 fulfilled,并将值传递到回调函数中。当 resolve() 方法被调用时,需要将 onFulfilledCallbacks 中的所有回调函数依次执行。

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

在上述代码中,我们判断当前 Promise 状态是否为 pending,如果是,将状态设置为 fulfilled,将值设置为传入的值,并执行 onFulfilledCallbacks 中所有的回调函数。

reject() 方法

reject() 方法用于将 Promise 状态设置为 rejected,并将错误信息传递到回调函数中。当 reject() 方法被调用时,需要将 onRejectedCallbacks 中的所有回调函数依次执行。

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

在上述代码中,我们判断当前 Promise 状态是否为 pending,如果是,将状态设置为 rejected,将错误信息设置为传入的错误信息,并执行 onRejectedCallbacks 中所有的回调函数。

then() 方法

then() 方法用于添加回调函数,它需要接收两个函数参数:onFulfilled 和 onRejected,分别代表 Promise 成功和失败的回调函数。

在 then() 方法中,我们需要判断 Promise 状态,如果 Promise 已经处于 fulfilled 或 rejected 状态,我们需要立即执行回调函数,如果 Promise 处于 pending 状态,我们需要将回调函数保存在 onFulfilledCallbacks 或 onRejectedCallbacks 中,等 Promise 转为 fulfilled 或 rejected 状态时再执行回调函数。

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

在上述代码中,我们首先创建一个新的 CustomPromise 对象,然后根据当前 Promise 状态执行相应的回调函数。如果当前状态为 fulfilled 或 rejected,我们立即执行回调函数并返回 promise 对象;否则,我们将回调函数保存在 onFulfilledCallbacks 或 onRejectedCallbacks 中,并返回 promise 对象,等待下一步执行。

完整实例

最后,让我们来看一下完整的 CustomPromise 实现:

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

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

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

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

示例代码

下面是一个使用自定义 Promise 的示例,它表示异步打印一个名字:

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

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

在上述代码中,我们调用 getName() 方法获取一个名字,利用 then() 方法获取名字并输出,如果发生错误则利用 catch() 方法处理错误。getName() 方法返回的是一个 CustomPromise 对象,它表示异步获取一个名字。

总结

通过本文的学习,我们掌握了如何使用 TypeScript 实现自定义 Promise,包括:定义 CustomPromise 类、实现 resolve()、reject() 和 then() 方法,并且完全符合 Promises/A+ 规范。自定义 Promise 可以帮助我们更好地理解 Promise 的原理和应用,并且在一些复杂场景下可以帮助我们更好地解决问题。

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

纠错
反馈