StuQ《Node.js微信开发》

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的办法。

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

async function a2() {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 1000);
  })
}

async function a1() {
  console.log("hello a1 and start a2");
  await a2();
  console.log("hello end a2");
}

async function a0() {
  console.log("hello a0 and start a1");
  await a1();
  console.log("hello end a1");
}

a0()

执行

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

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

异常处理

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

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

try {
  console.log(await asyncFn());
} catch (err) {
  console.error(err);
}

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

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

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

Async函数总结

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