ES6之async+await 同步/异步方案( 二 )


其中 , 1 说明了从外部看 , task 方法执行后返回一个 Promise 对象 , 正因为它返回的是 Promise , 所以可以理解task 是一个异步方法 。 毫无疑问它是这样用的:

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



62说明了在 task 函数内部 , 异步已经被 “削” 成了同步 。 整个就是一个执行稍微耗时的函数而已 。
综合 1、2 , 从形式上看 , 就是 “task 整体是一个异步函数 , 内部整个是同步的” , 简称“外异内同” 。
整体是一个异步函数 不难理解 。 在实现上 , 我们不妨逆向一下 , 语言层面让async关键字调用时 , 在函数执行的末尾强制增加一个promise 反回:

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



7实际上 await 调用 , 是让后边的语句(函数)做了一个递归执行 , 直到获取到结果并使其 状态 变更 , 才会 resolve 掉 , 而只有 resolve 掉 , await 那一行代码才算执行完 , 才继续往下一行执行 。 所以 , 尽管外部是一个大大的 for 循环 , 但是整个 for 循环是依次串行的 。
因此 , 仅从上述框架的外观出发 , 就不难理解 async + await 的意义 。 使用起来也就这么简单 , 反而 Promise 是一个必须掌握的基础件 。
秉承本次《重读 ES6》系列的原则 , 不过多追求理解细节和具体实现过程 。 继续巩固一下这个 “形式化” 的理解 。
async + await 的进一步理解
有这样的一个异步操作 longTimeTask , 已经用 Promise 进行了包装 。 借助该函数进行一系列验证 。

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



8以上 2 步执行 , 清晰的证明了 exec1 函数体内是同步、逐行逐行执行的 , 即先执行完异步操作 , 然后进行 console.log() 打印 。 而 exec1() 的执行结果就直接是一个 Promise , 因为它最先会蹦出来一串 Promise ... , 然后才是 exec1 函数的内部执行日志 。
因此 , 所有验证 , 完全符合 整体是一个异步函数 , 内部整个是同步的 的总结 。
await 如何执行其后语句
回到 await  , 看看它是如何执行其后边的语句的 。 假设:让 longTimeTask() 后边直接带 then() 回调 , 分两种情况:
1)then() 中不再返回任何东西2) then() 中继续手动返回另一个 promise

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



9longTimeTask() 加上再多得 then() 回调 , 也不过是放在了它的回调列队 queue 里了 。 也就是说 , await 命令之后始终是一条 表达式语句 , 只不过上述代码书写方式比较让人迷惑 。 (比较好的实践建议是 , 将 longTimeTask 方法身后的 then() 移入 longTimeTask 函数体封装起来)
其次 , 手动返回另一个 promise 和什么也不返回 , 关系到 longTimeTask() 方法最终 resolve 出去的内容不一样 。 换句话说 , await 命令会提取其后边的promise 的 resolve 结果 , 进而直接导致 result 的不同 。
值得强调的是 , await 命令只认 resolve 结果 , 对 reject 结果报错 。 不妨用以下的 return 语句替换上述 return 进行验证 。

猜你喜欢