解决 Javascript 异步编程的利器 ——Promise 详解

阅读时长 10 分钟读完

Javascript 是一门异步编程语言。异步编程使得 Javascript 在网络请求、文件读写等场景下表现优异。然而,异步编程也带来了 Callback Hell(回调地狱)和代码可读性差等问题。Promise 就是用来解决这些问题的利器。

什么是 Promise

Promise 是一个代表了异步操作的最终完成或失败的对象。它可以避免 Callback Hell,提高代码的可读性和维护性。Promise 有三种状态:Pending(等待中)、Fulfilled(已完成)和Rejected(已失败)。当 Promise 被创建时,它处于 Pending 状态。当异步操作完成后,Promise 会进入 Fulfilled 状态;如果异步操作失败,则 Promise 进入 Rejected 状态。

Promise 的基本用法

Promise 提供了一个 then 方法,用于在 Promise 进入 Fulfilled 或 Rejected 状态时进行回调处理。then 方法接收两个参数:onFulfilled(成功时回调)和 onRejected(失败时回调)。

例如,下面的代码使用 Promise 发起一个 API 请求,并在请求成功后输出结果,请求失败后输出错误信息。

-- -------------------- ---- -------
--------------------------------
  ------------------------ -
    ------ ----------------
  --
  -------------------- -
    ------------------
  --
  ---------------------- -
    -------------------- -------- -------
  ---
展开代码

当 Promise 进入 Fulfilled 状态时,then 方法会返回一个新的 Promise,因此可以链式调用多个 then 方法进行处理。then 方法会将前一个 Promise 返回的值作为参数传递给后一个 Promise。

例如,下面的代码使用 Promise 计算两个数相加的结果,并在计算完成后输出结果。

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

------ --
  ------------------- -
    ------ -------- ---
  --
  ------------------- -
    -----------------
  ---
展开代码

Promise 的进阶用法

Promise 还提供了一些进阶用法,例如 all、race 和 finally 方法。

all 方法

Promise.all 方法接收一个 Promise 数组作为参数,返回一个新的 Promise。当所有 Promise 都进入 Fulfilled 状态时,该新的 Promise 进入 Fulfilled 状态,并将所有 Promise 返回的结果以数组形式传递给后续的 then 方法;当其中任意一个 Promise 进入 Rejected 状态时,该新的 Promise 进入 Rejected 状态。

例如,下面的代码使用 Promise.all 方法实现并行调用多个 API,等待所有结果返回后输出结果。

-- -------------------- ---- -------
-------------
  --------------------------------------------------------- -
    ------ ----------------
  ---
  --------------------------------------------------------- -
    ------ ----------------
  --
--
  ----------------------- -
    ----------------------- ------------
  --
  ---------------------- -
    -------------------- -------- -------
  ---
展开代码

race 方法

Promise.race 方法接收一个 Promise 数组作为参数,返回一个新的 Promise。只要有一个 Promise 进入 Fulfilled 或 Rejected 状态,该新的 Promise 就进入相应的状态。它的用途是:Race to finish.

例如,下面的代码使用 Promise.race 方法实现同时发起多个 API 请求,等待任意一个结果返回后输出结果。

-- -------------------- ---- -------
--------------
  --------------------------------------------------------- -
    ------ ----------------
  ---
  --------------------------------------------------------- -
    ------ ----------------
  --
--
  ---------------------- -
    --------------------
  --
  ---------------------- -
    -------------------- -------- -------
  ---
展开代码

finally 方法

Promise.finally 方法接收一个回调函数作为参数,在 Promise 进入 Fulfilled 或 Rejected 状态时均会执行该回调函数。它的作用是进行清理工作或更新 UI 状态。

例如,下面的代码使用 Promise.finally 方法实现在请求完成后隐藏进度条。

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

--------------------------------
  ------------------------ -
    ------ ----------------
  --
  -------------------- -
    ------------------
  --
  ---------------------- -
    -------------------- -------- -------
  --
  ------------------- -
    ------------------------- - -------
  ---
展开代码

Promise 的错误处理

Promise 的错误处理可以用两种方式实现:使用 catch 方法和在 then 方法中使用第二个参数。

catch 方法

catch 方法用于捕获 Promise 进入 Rejected 状态时抛出的错误,并进行处理。它接收一个回调函数作为参数,该回调函数的参数是错误对象。

例如,下面的代码使用 Promise.catch 方法捕获并输出请求错误信息。

-- -------------------- ---- -------
--------------------------------
  ------------------------ -
    ------ ----------------
  --
  -------------------- -
    ------------------
  --
  ---------------------- -
    -------------------- -------- -------
  ---
展开代码

then 方法的第二个参数

then 方法的第二个参数用于处理 Promise 进入 Rejected 状态时抛出的错误。它的作用等同于 catch 方法。

例如,下面的代码使用 Promise.then 方法的第二个参数捕获并输出请求错误信息。

-- -------------------- ---- -------
--------------------------------
  ------------------------ -
    ------ ----------------
  -- --------------- -
    -------------------- -------- -------
  --
  -------------------- -
    ------------------
  ---
展开代码

Promise 的实现

Promise 规范是由 Promises/A+ 组织制订的,任何符合该规范的实现都称为 Promise。在 ES6 中,Promise 已经是内置对象;在 ES5 中,可以通过第三方库实现 Promise,例如 Q 和 Bluebird 等。

下面是一个简单的 Promise 实现,只用于演示用途。

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

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

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

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

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

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

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

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

  ----------- --------
-
展开代码

结论

Promise 是解决 Javascript 异步编程的利器,它可以避免 Callback Hell,提高代码的可读性和维护性。Promise 还提供了一些进阶用法,例如 all、race 和 finally 方法。我们可以使用内置的 Promise 对象,也可以使用第三方库实现 Promise。优秀的前端工程师应该精通 Promise,并在项目中加以应用。

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

纠错
反馈

纠错反馈