
3.13 async/await
请尝试想象以下场景:当使用Promise时,有一种方式告诉运行时的JavaScript暂停执行await关键字之后的内容,直到Promise从一个函数中执行完成。

当Promise完成时,将继续执行await关键字之后的代码。
● 如果成功完成,那么它会返回一个值。
● 如果它被拒绝,将同步抛出一个错误,我们可以用catch来捕获这个错误。
这突然且神奇地使异步编程变得像同步编程一样简单,这个实现需要3件事情。
● 能够停止函数执行。
● 能够在函数中放置一个值。
● 能够在函数内部抛出异常。
这正是generators允许我们做的事情,这个实验其实是真实的,async/await在JavaScript/TypeScript中正是这么实现的,它的背后只是使用了generators。
1.产生JavaScript
你不必理解这些,如果你已经阅读了generators就会发现它真的很简单。函数foo可以简单包装如下。


在上述代码中,wrapToReturnPromise执行generators函数来获取generators,接着使用generator.next(),如果值是Promise,则它会捕获Promise,并根据其结果调用generator.next(result)或generator.throw(error)。
2.TypeScript对async/await的支持
TypeScript从1.7版本之后开始支持async/await。异步函数以async关键字为前缀,await将暂停执行,直到异步函数返回Promise执行完成的结果,并且返回非Promise包装后的值。它只有在编译目标为ES6时支持async/await,并将其编译成ES6 generators。
TypeScript 2.1版本添加了ES3和ES5运行时的功能,这意味着无论你在何种环境下,都可以自由地使用它。值得注意的一点是,我们可以在TypeScript 2.1版本中使用async/await,许多浏览器都支持它。当然,你需要为Promise添加全局的polyfill。
下面让我们来看看TypeScript中的async/await是如何运行的,示例如下。


1)编译到ES6(--target es6)


2)编译到ES5(--target es5)






完整的示例见参考资料[5]。
注意:对于这种有两种编译目标的场景,我们都需要确保运行时在全局下有一个符合ECMAScript规范的Promise,它可能是一个Promise的polyfill。同样,我们也需要确定TypeScript知道Promise的存在,这可以通过将lib标记设置为dom、es2015、dom、es2015.promise、es5来实现。在参考资料[6]中,可以看到支持Promise(包括native和polyfill)的浏览器都有哪些。