JavaScript 异步编程技巧:从回调到 Promise

阅读时长 6 分钟读完

异步编程的背景

JavaScript 的执行环境是单线程的,这决定了一旦有阻塞操作,就会影响整个程序的执行。为了避免阻塞,JavaScript 采用了异步编程模式。从最开始的回调函数,到后来的 Promise 和 async/await,JavaScript 在异步编程方面不断演进并提供了更好的编程模式。

回调函数

一开始,JavaScript 中异步编程的方式只有回调函数。回调函数就是在一个异步操作执行完毕后,将结果传递给一个函数。如下面的代码:

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

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

这里的 getData 函数是一个异步函数。因为它调用了 setTimeout,所以无法立即返回结果。为了获取到 getData 函数执行完毕后的数据,我们需要传入一个回调函数作为参数。在异步函数执行完毕后,将数据传递给回调函数并执行。

但是,如果我们需要进行多次异步操作,就会发现回调函数会嵌套得非常深。这就是所谓的“回调地狱”。如下面的代码:

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

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

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

上面的代码演示了回调地狱是如何发生的。如果我们需要进行更多的异步操作,代码将会变得难以理解和维护,而且任何一处错误都会造成整个程序的崩溃。

Promise

为了解决回调地狱的问题,Promise 出现了。Promise 是一个对象,它代表着一个尚未完成的异步操作。Promise 可以处于以下三种状态中的一种:

  • pending:初始状态,尚未执行也没有被拒绝。
  • fulfilled:执行成功,Promise 的操作已经完成并返回了一个值。
  • rejected:执行失败,Promise 操作抛出了一个错误或者拒绝了一个值。

Promise 通过 then 方法将异步操作的结果传递给一个或多个回调函数。这些回调函数将在异步操作完成时被执行。如下面的代码:

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

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

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

Promise 能够解决回调地狱的问题,因为它们可以在 .then 方法中链接起来,而不是嵌套地写一个回调函数。但是,Promise 也有一些问题。例如,Promise 内部的错误很难捕获,而且 Promise 本身的状态无法被取消。

async/await

async/await 是 Promise 的扩展。这个特性允许我们使用类似同步代码的方式来写异步代码。async/await 允许我们使用 await 操作符来等待一个 Promise 对象被解决,然后返回 Promise 对象的值。如下面的代码:

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

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

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

-------

async/await 让我们可以使用类似同步代码的方式来写异步代码。它也提供了一种更容易捕捉错误的方式,并且可以取消执行的异步操作。但是,使用 async/await 时要注意不能在循环中使用 await,否则会阻塞线程。并且,使用 async/await 时要谨慎处理错误,否则可能造成程序的崩溃。

结论

异步编程是 JavaScript 开发中不可避免的问题。从最开始的回调函数,到后来的 Promise 和 async/await,JavaScript 在异步编程方面不断演进并提供了更好的编程模式。使用这些技术可以更方便地编写异步代码,并且避免了回调地狱的问题。不过,这些技术也有它们自己的限制和问题,需要谨慎使用和处理。

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

纠错
反馈