原文地址: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的Promises。Promise基本上是表示异步操作的最终完成(或失败)及其结果值的对象。

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的主要功能之一,它具有突出的特点。最后,我们可以使用try和catches来处理同步和异步错误,而不能重复try-catch块对于promises来说是一种痛苦。
良好的旧Promise世界的下一个最好的改进是代码调试。当我们编写基于箭头函数的promises时,我们不能在箭头函数中设置断点,因此有时调试很困难。但是使用async/awaits,调试就与如何调试同步代码一样。
我相信到现在你已经对javascript中的异步编程有了更好的理解。