异步编程的背景
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