[译]每个JS开发人员应该知道的异步编程基础知识

232 阅读4分钟

原文地址:Async programming basics every JS developer should know

本文的目的是让大家开始使用javascript中的异步编码,这样我们就可以通过箭头函数,模板文字等来保持简单。

回调是现代javascript函数式编程中最常用的概念之一,如果你曾经使用过jQuery,你很可能已经使用过回调而不知道。

什么是回调函数?

最简单的回调函数是作为参数传递给另一个函数的函数。然后,回调函数在传递函数内执行,最终将结果返回给调用者。

简单吧?现在让我们实现一个回调函数来获得游戏中level的分数。

进入startGame()函数后,我们将currentScore和回调函数作为参数调用函数levelOne()

当我们在startGame()内部作用域调用levelOne()函数,JavaScript用异步方式执行levelOne()函数,主线程继续执行代码的剩余部分。

既然不会阻止主线程,这意味着我们可以执行所有类型的操作,例如从API获取数据,进行一些数学运算等,所有这些都是耗时的。一旦function(levelOne())完成了它的操作,它就可以执行我们之前传递的回调函数。

这是函数式编程非常有用的功能,因为回调让我们异步处理代码,而不必等待响应。例如,您可以使用回调函数对慢速服务器进行ajax调用。并完全忘记它并继续你剩下的代码。一旦该ajax调用得到解决,回调函数就会自动执行。

但是如果要在嵌套多级回调,回调可能会变得很糟糕。让我们以上面的例子为游戏添加更多关卡。

等等,刚刚发生了什么?我们对level增加了两个新的功能,levelTwo()levelThree()。在levelOne的内部回调(第22行)中,通过回调函数和levelOne的回调结果调用levelTwo()函数。并再次为levelThree()函数重复相同的操作。

现在想象一下,如果我们必须为另外10个level实现相同的逻辑,那么这个代码将成为什么。你已经恐慌了吗?随着嵌套回调函数的数量增加,读取代码变得更加困难,甚至更难调试。

这通常被称为回调地狱。有没有办法解决这个回调地狱?

Promises有更好的方法

Javascript开始支持ES6的PromisesPromise基本上是表示异步操作的最终完成(或失败)及其结果值的对象。

让我们尝试用promises重写回调地狱示例。

我们重新编写了level(One/Two/Three)函数来从函数参数中删除回调,不是在其中调用回调函数,而是用promises替换。

解决startGame之后,我们可以简单地调用一个.then()方法处理结果。我们可以一个接一个地链接多个.then()

这使得整个代码在正在执行中以及then接下来发生的操作等方面更具可读性和易于理解。

promise更好的深层原因是它们更具有组合性,这意味着将多个promises组合起来“正常”,而组合多个回调通常不会。

此外,当我们有一个回调而不是一个Promise时,它确实没有明显差异。当你拥有大量的回调和许多Promise时,基于Promise的代码往往看起来更好。

好吧,我们已成功从回调地狱中逃脱,并使我们的代码在Promise中具有很强的可读性。但是如果我告诉你有方法可以使它更清洁,更具可读性呢?

(a)Wait

自ECMA2017以来,javascript支持Asyn/await 。它们允许编写基于Promise的代码,就像它是同步代码一样,但不会阻塞主线程。它们使异步代码不那么“高明”,更具可读性。

说实话,async/awaits只不过是Promise之上的语法糖,但它使异步代码的外观和行为更像是同步代码,这正是它的力量所在。

如果async在函数定义之前使用关键字,则可以在函数内使用await。当你await一个promise时,函数会以非阻塞的方式暂停,直到promise解决。如果promise fulfilled,将获得value。如果promise rejected,则thrown rejected value

现在来看看我们的游戏逻辑看起来如何用async/awaits重写它!

我们的代码立即变得更具可读性,Async/await还有更多功能。

错误处理Async/await的主要功能之一,它具有突出的特点。最后,我们可以使用trycatches来处理同步和异步错误,而不能重复try-catch块对于promises来说是一种痛苦。

良好的旧Promise世界的下一个最好的改进是代码调试。当我们编写基于箭头函数的promises时,我们不能在箭头函数中设置断点,因此有时调试很困难。但是使用async/awaits,调试就与如何调试同步代码一样。

我相信到现在你已经对javascript中的异步编程有了更好的理解。