原文地址:
异步函数在JavaScript中有好有坏。好的一面是异步函数是非阻塞的,因此很快 - 特别是在Node.js上下文中。缺点是处理异步函数可能很麻烦,因为有时必须等待一个函数完成才能在进行下一次执行之前获得“回调”。
有一些方法可以发挥异步函数调用的优势并正确处理它们的执行,但其中一种方法远远优于其他方法(Spoiler:它是Async / Await)。在本文中,您将了解使用和的来龙去脉,以及我们对两者之间如何比较的看法。
Promises vs. Callbacks
作为JavaScript或Node.js开发人员,正确理解Promises
和Callbacks
之间的区别以及它们如何协同工作至关重要。
两者之间存在微小但重要的差异。在每个Promise
的核心,都有一个Callback
解决某些数据(或错误),这些数据会被调用到Promise
。
回调处理程序:
调用validatePassword()功能: 下面的代码片段显示了验证密码的完整端到端检查(它是静态的,必须匹配“bambi”): 代码注释得非常好,但是,如果您感到困惑,catch
只会在 reject()
从 promise
调用时执行。由于密码不匹配,我们调用 reject()
,因此 “catch”
错误并将其发送到 done()
函数。 Promises
与传统的基于回调的方法相比,Promise
为执行、组合和管理异步操作提供了更简单的替代方案。它们还允许你使用类似同步try / catch
的方法处理异步错误。
Promise还提供三种唯一的状态:
Pending
-promise
的结果尚未确定,因为将产生其结果的异步操作尚未完成。Fulfilled
- 异步操作已完成,并且promise
有值。Rejected
- 异步操作失败,promise
永远不会实现。在被拒绝状态下,promise
有一个reason
可以指示操作失败的原因。
当promise
在pending
状态时,它可以转换为fulfilled
或rejected
的状态。然而,一旦promise
得到fulfilled
或rejected
,它将永远不会过渡到任何其他状态,其value
或失败原因不会改变。
缺点?
Promise
不做的一件事是解决所谓的“回调地狱”(原文:The one thing promises don’t do is solve what is called “callback hell”, which is really just a series of nested function calls. ),“回调地狱”实际上只是一系列嵌套函数调用。当然,对于一个调用没关系。但是对于多个调用,您的代码将会难以阅读和维护。
在Promises中循环?
为了避免使用JavaScript进行深度嵌套回调,假设可以简单地遍历Promises
,将结果返回给对象或数组,并在完成后停止。不幸的是,这并不容易; 由于JavaScript的异步特性,如果循环遍历每个Promise
,在代码完成时不会调用“done”
事件。
处理这种情况的正确方法是使用Promise.all()
。这个函数在它被标记为已完成之前等待所有的Fulfillments
(或第一次rejection
)。
错误处理?
使用多个嵌套的Promise
调用进行错误处理就像蒙着眼睛的驾驶汽车一样。祝你好运找出哪个Promise
犯了错误。你最好的选择是完全删除catch()
方法并选择加入全局错误处理程序,如下所示:
浏览器:
Node.js: 注意:以上两个选项是确保捕获错误的两种方法。如果错过了添加catch()
方法,它将被代码吞噬。 Async/Await??
Async/Await
允许我们编写看起来是同步的异步JavaScript。在本文的前几部分中,您了解了Promises
- 它应该简化异步流并避免回调地狱但它没有。
回调地狱??
Callback-hell
是一个用于描述以下场景的术语:
注意:举个例子,这是一个API调用,可以从一个数组中获得4个特定用户。
这样的代码这很难看,也占用了大量的空间。Async/Await
是JavaScript的最新和最好的东西,它允许我们不仅避免回调地狱,而且确保我们的代码干净并且错误被正确捕获。我发现Async/Await
最令人着迷的是它构建在Promises
之上(非阻塞等),并且允许代码可读并且就像读取它是同步的一样。这就是关键所在。
代码这样写比较优雅,对吗??注意:以下是一组API调用的示例,用于从一个数组中检索4个用户,超过一半的代码行:
因为Async/Await
是建立在Promises之上的,所以你甚至可以在关键字await
使用Promise.all()
:
Async/await
稍微慢一些。连续多次使用它时应该小心,因为 await
关键字会停止执行后面的所有代码 - 就像在同步代码中一样。 如何开始使用Async/Await??
使用Async/Await
非常容易理解和使用。实际上,它可以在最新版本的Node.js中本地使用,并且正在迅速融入浏览器。现在,如果你想在客户端使用它,你需要使用Babel。
异步Async
让我们从async
关键字开始。它可以放在function
之前,如下所示:
等待Await
关键字await
使JavaScript等待promise
继续并返回其结果。如下所示:
为什么Async/Await更好??
现在我们已经了解了Promises
和Async/Await
所提供的很多内容,让我们回顾一下为什么认为Async/Await
是代码库的最佳选择。
Async/Await
允许使用更少的代码行,更少的输入和更少的错误,提供简洁明了的代码库。最终,它使复杂的嵌套代码再次可读。- 使用
try/catch
处理错误(在一处,而不是在每个调用中) - 错误堆栈是有意义的,而不是从
Promises
收到的模糊错误,它们很大并且很难找到错误发生的位置。最重要的是,错误指向错误发生的函数。
最后的想法?
可以说Async/Await
是过去几年中添加到JavaScript中的最强大的功能之一。
花了不到一天的时间来理解语法,看看我们的代码库在这方面是多么糟糕。将我们所有基于Promise
的代码转换为Async/Await
总共花费了大约两天时间,这实际上是一个完全重写 - 这只是为了说明使用Async/Await时需要更少的代码。