ES6之async+await 同步/异步方案

异步编程一直是JavaScript 编程的重大事项 。 关于异步方案 ,  ES6 先是出现了 基于状态管理的 Promise , 然后出现了 Generator 函数 + co 函数 , 紧接着又出现了 ES7 的 async + await 方案 。
本文力求以最简明的方式来疏通 async + await 。
工具/原料JavaScript
方法/步骤1异步编程的几个场景
先从一个常见问题开始:一个for 循环中 , 如何异步的打印迭代顺序
用闭包或者ES6 规定的 let 块级作用域来回答这个问题 。

ES6之async+await 同步/异步方案

文章插图

2这里描述的是一个均匀发生的的异步 , 被依次按既定的顺序排在异步队列中等待执行 。
如果异步不是均匀发生的 , 那么被注册在异步队列中的顺序就是乱序的 。

ES6之async+await 同步/异步方案

文章插图

3返回的结果是乱序不可控的 , 这本来就是最为真实的异步 。 另一种情况是 , 在循环中 , 如果希望前一个异步执行完毕、后一个异步再执行 , 该怎么办?

ES6之async+await 同步/异步方案

文章插图

4这不就是多个异步 “串行” 
在回调 callback 嵌套异步操作、再回调的方式 , 不就解决了这个问题!或者 , 使用 Promise + then() 层层嵌套同样也能解决问题 。 但是 , 如果硬是要将这种嵌套的方式写在循环中 , 还恐怕还需费一番周折 。
异步同步化方案
【ES6之async+await 同步/异步方案】如果要去将一批数据发送到服务器 , 只有前一批发送成功(即服务器返回成功的响应) , 才开始下一批数据的发送 , 否则终止发送 。 这就是一个典型的 “for 循环中存在相互依赖的异步操作” 的例子 。
明显 , 这种 “串行” 的异步 , 实质上可以当成同步 。 它和乱序的异步比较起来 , 花费了更多的时间 。 按理说 , 我们希望程序异步执行 , 就是为了 “跳过” 阻塞 , 较少时间花销 。 但与之相反的是 , 如果需要一系列的异步 “串行” , 我们应该怎样很好的进行编程?
对于这个 “串行” 异步 , 有了 ES6 就非常容易的解决了这个问题 。

ES6之async+await 同步/异步方案

文章插图

5本次循环 , 等有了结果 , 再进行下一次循环 。 因此 , 循环每执行一次就会被暂停(“卡住”)一次 , 直到循环结束 。 这种编码实现 , 很好的消除了层层嵌套的 “回调地狱” 问题 , 降低了认知难度 。
这就是异步问题同步化的方案 。 如果说 Promise 主要解决的是异步回调问题 , 那么 async + await 主要解决的就是将异步问题同步化 , 降低异步编程的认知负担 。
async + await “外异内同”
早先接触这套 API 时 , 看着繁琐的文档 , 一知半解的认为 async + await 主要用来解决异步问题同步化的 。
其实不然 。 从上面的例子看到:async 关键字声明了一个 异步函数 , 这个 异步函数 体内有一行 await 语句 , 它告示了该行为同步执行 , 并且与上下相邻的代码是依次逐行执行的 。
将这个形式化的东西再翻译一下 , 就是:
1、async 函数执行后 , 总是返回了一个 promise 对象2、await 所在的那一行语句是同步的

推荐阅读