- Promise 和Generate是ECMAScript 2015 的特性,Async/Await是ECMAScript 2017新添加的特性。
- Promise,Generate 和 Async/Await 都是为了使异步处理更加优雅的特性。参见我的另一篇博客 Nodejs 异步处理的演进
Promise 函数
Generator 函数
thunkify与co如何实现对generator 函数的流程控制
Async/Await 函数
下面是学习总结,没有代码或流程图,建议先阅读上面链接。
Promise对象
虽然优化了大量回掉函数所带来代码的繁琐,但是大量使用Promise 容易陷入连续then 函数的调用。如果需求是多个串行non-blocking I/O 函数,这样就要在Promise 对象中嵌套Promise对象,这与瀑布级的回调大同小异。-
Generaor 函数
调用Generator 函数后,函数并不会执行,返回的是一个指向内部状态的指针对象。因此必须调用遍历器对象的next方法,使得指针指向下一状态。因此Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。虽然Generator 对象看似解决瀑布级回调函数的繁琐,但是执行Generator 函数需要频繁的调用next 函数。如果多个Generator函数串联顺序执行的任务,还需要在下个next函数执行时将上一个yield的返回值传递给函数。为了优雅解决Generator函数调用的难题,DJ大神(心中膜拜的对象)先后写了两个开源库thunkify 和co。
thunikify 库
原理来源于thunk函数(在Javascript 中thunk 函数是将多参函数替换为只接受回调函数的单参函数),当我需要把non-blocking 的I/O 函数封装成Generator 对象时,只需要按照以下步骤参照 Generator 函数:
1. 把函数用thunkify 库封装
2. 把封装后的函数放在Generator 函数体中yield 关键字后面
3. 执行Generator 函数,通过向gen().next().value()中传递回调函数
虽然这样很方便实现non-bloking 的I/O 函数向Generator函数的封装,但是执行generator 函数时又是一堆瀑布级的调用。大神之所以为大神就是在自己的领域内精益求精,因此co 库应运而生。co 库
实际就是一个generator 函数的自动执行器。要求Generator 函数中的yield 部分必须是Promise 函数,调用时只需要引用co 库并且把执行的Generator 函数名作为参数,这样就可以坐等结果了。即便co 完美的解决了Generator 函数的状态级的便利与执行,由于强烈依赖于第三方库,它注定只是no-blocking I/O 的临时过渡方案。Async/Await 函数
1. 相较于Generator 函数, Async/Await 函数是自带遍历执行器。
2. async和await,比起星号和yield,语义更清楚了。
async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。async函数的返回值是 Promise 对象,await 后执行的函数也必须是Promise 对象,这一点与co 库想类似(伟大的灵魂总是那么的相似)。到这里我们终于可以优雅且简洁的执行non-blocking I/O 函数了,但是需要注意,如果是多个串行的Promise函数一次执行,靠前的Promise 函数出现exception 就会直接block 当前async 函数的往下面执行,因此要做必要的exception 的处理。另外,如过async函数体内是多条并行的Promise 函数,建议使用Promise.all()方法。