Async函数/Await(以前说是ES7 stage-3)

Generator的弊病是没有执行器,它本身就不是为流程控制而生的,所以co的出现只是解决了这个问题。

可是,你不觉得奇怪么?为什么非要加个co,才能好好的玩耍?为什么不能是直接就可以执行,并且效果和Yieldable一样的呢?

Async/Await 就是这样被搞出来的,很多人认为它是异步操作的终极解决方案。

Await

Await的3种可能情况

  • Await + Async函数
  • Await + Promise
  • await + co(co会返回Promise,这样可以Yieldable,但难度较大,适合老手)

头2种是比较常用的,第三种co作为promise生成器,是一种hack的办法。

下面给出第一种和第二种的示例:

  1. async function a2() {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(resolve, 1000);
  4. })
  5. }
  6. async function a1() {
  7. console.log("hello a1 and start a2");
  8. await a2();
  9. console.log("hello end a2");
  10. }
  11. async function a0() {
  12. console.log("hello a0 and start a1");
  13. await a1();
  14. console.log("hello end a1");
  15. }
  16. a0()

执行

需要使用babel或者其他支持async函数的编译工具,这里使用runkoa(是为koa支持async函数做的基于babel的简单封装)

  1. $ runkoa async.js
  2. async.js
  3. 3babel presets path = /Users/sang/.nvm/versions/node/v4.4.5/lib/node_modules/runkoa/node_modules/
  4. hello a0 and start a1
  5. hello a1 and start a2
  6. hello end a2
  7. hello end a1

异常处理

Node.js里关于异常处理有一个约定,即同步代码采用try/catch,非同步代码采用error-first方式。对于Async函数俩说,它的Await语句是同步执行的,所以最正常的流程处理是采用try/catch语句捕获,和generator/yield是一样的。

下面的代码所展示的是通用性的做法:

  1. try {
  2. console.log(await asyncFn());
  3. } catch (err) {
  4. console.error(err);
  5. }

很多时候,我们需要把异常做得粒度更细致一些,这时只要把Promise的异常处理好就好了。

Promise里有2种处理异常的方法

  • then(onFulfilled, onRejected)里的onRejected,处理当前Promise里的异常
  • catch处理全局异常

Async函数总结

  • Async函数语义上非常好
  • Async不需要执行器,它本身具备执行能力,不像Generator
  • Async函数的异常处理采用try/catch和Promise的错误处理,非常强大
  • Await接Promise,Promise自身就足够应对所有流程了
  • Await释放Promise的组合能力,外加Promise的then,基本无敌