Node.js:使用 Async 和 Await 处理异步过程

在 Node.js 中,处理异步操作是一项非常重要的技能。在过去,我们通常使用回调函数和 Promise 等方式来处理异步过程。但是,这些方法缺乏直观性,很难编写和维护。随着 ES6 的推出,我们的异步操作处理方法也有了进一步的改进,Async 和 Await 就是其中一个重要的进展。

Async 和 Await

Async 和 Await 是 ES2017 中引入的新特性,简化了异步操作的编写和执行。Async 函数是 Promise 函数的一种语法糖,它简化了 Promise 的使用语法,而 Await 就是 Async 函数的关键字,用来等待 Promise 完成。

在使用 Async 和 Await 之前,我们需要了解 Promise 对象。

Promise

Promise 是异步操作的一种解决方式。在 Promise 中,我们可以将异步操作包装进 Promise 实例中,当操作完成后,Promise 实例会返回一个成功(resolve)或失败(reject)的值。

Promise 的使用方式如下:

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

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

在以上代码中,Promise 中包装了一个异步操作,使用 setTimeout 模拟异步操作,1 秒后将返回值传递给 resolve 函数。在 Promise 实例中,使用 then 和 catch 方法处理 Promise 返回的值。当 Promise 成功时,then 方法会执行,在 then 方法中可以操作 Promise 返回的值;当 Promise 失败时,catch 方法会执行,在 catch 方法中可以处理 Promise 返回的错误信息。

Async 函数

Async 函数是 Promise 函数的一种简化写法。Async 函数会自动将返回值包装成 Promise 对象,这样我们就不需要手动创建 Promise 对象。Async 函数的声明方式如下:

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

以上的代码就声明了一个 Async 函数。把异步操作写在该函数中即可。Async 函数会自动将返回值封装为 Promise 对象。当 Async 函数内部使用 return 语句返回值时,Async 函数会自动将该值包装成 Promise.resolve(value) 的形式;当 Async 函数内抛出错误时,Async 函数会自动将错误信息包装成 Promise.reject(error) 的形式。

下面是使用 Async 函数实现异步操作的示例代码:

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

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

上述代码中,asyncOperation 函数用来封装异步操作,返回的是 Promise 对象。在异步操作完成后,Promise 对象会为其赋值,当该 Promise 完成后,使用 then 和 catch 两个方法来检查异步操作的结果。

Await 关键词

在 Async 函数中,使用 await 关键字可以等待异步操作结果。在使用 await 时,该关键字必须放在 Async 函数中。

下面是一个使用 await 关键字的示例代码:

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

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

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

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

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

在上述代码中,我们写了一个 delay 函数来模拟延时操作,Async 函数中使用 await 关键字等待 delay 函数的返回值,当 delay 函数返回一个 Promise 对象,并且这个对象被 resolve 了之后,await 才会返回数据,从而完成整个异步流程。

我们也可以使用 try/catch 来处理错误,示例代码如下:

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

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

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

在上述代码中,我们对 delayReject 函数返回的 Promise 对象中止整个 Async 函数。如果 delayReject 函数返回的 Promise 被 reject,那么会跳到 catch 语句块,并处理错误。

Async 和 Await 的使用场景

Async 和 Await 分别代表异步和等待,使用这两个关键字的代码大幅度提高了代码的可读性。Async 和 Await 的代码还能避免 Promise 和回调函数中的嵌套问题。当我们使用异步 API 和异步操作时,消息传递可以避免嵌套问题,使得代码更易读。

下面看一个常见场景的代码:

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

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

让我们用 await 重写一下:

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

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

上述代码中,我们使用一个函数 asyncOperation 来封装延迟操作。在 main 函数中使用 await 使得每个异步操作等待被处理,同时避免了 Promise 在代码中的嵌套。

结论

Async 和 Await 相对于 Promise 和回调函数解决了很多问题。与 Promise 相比较,Async 和 Await 的代码更加直观,易读,可维护性也更好。虽然使用 Async 和 Await 很方便,但是它并不是对所有场景都适用。例如,当我们需要同时触发多个异步操作,然后在所有异步操作完成后才执行一些处理的任务时,Promise 可能更加适合。

总之,当我们需要处理异步操作时,使用 Async 和 Await 这一新特性可以让我们的代码看起来更加优雅和简单,同时也可以在性能上得到提升。

参考文献

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