http://node.green/#async-functions
Node 的最大特性之一就是 Single Thread, Event-Drive, Asynchronous I/O。
因为是单线程,注定是不能长时间空等占用线程,JS 的解决方案是 Asynchronous Event,当有事件通知到时做响应,需要等待时,将控制权交出。
对于 Asynchronous,那真是有太多的方案了,我们从头开始看:
## Callback
最早通过 Callback 来实现 Event-Drive。
1 | function f1(callback){ |
callback 的原理就是我向事件中心注册这么一个事件,当执行到我时,事件中心来调用我这个事件。
Callback Hell
当然 Callback 有着最大的天然缺陷,不符合人类思维,当项目变大,嵌套变深时,callback 的写法,将是一个灾难:
## Promise
Promise 对象可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
Promise 是一个有限状态机(有 Pending, Resolved, Rejected 三种状态),一旦创建后立即执行,可以由 Pending 到另外两种,状态一旦改变后就不能再次更改,会一直保持。
和 Callback 不同的是,状态会一直保持,在 Promise 执行完成后,依然可以添加回调 (then)。
原理就是有一个队列,回调时从里面取出,放到 Event Queue 中。
将传统的 Callback 封装成 Promise 来使用。
1 | const asyncStringify = (content) => { |
Promise 创建后立即执行,然后可以用 then 方法分别指定 Resolved 状态和 Reject 状态的回调函数。
1 | promise.then(function(value) { |
Bluebrid
Bluebrid 提供了方法,可以直接将 所有的 Callback 直接返回全新的 promise。
这里我们的 系统的 FileStream 模块的所有函数给转成 Promise 函数。
1 | import bluebird from 'bluebird'; |
Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。
Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。
## Generator
Generator 是一个无限状态机。
Syntax
1 | function *foo() { |
DEMO
1 | function *helloWorldGenerator() { |
和普通 function 有点不同的是,这个函数并不会执行,返回的也不是结果,而是指向内部状态的指针对象(遍历器),普通函数中,是不能指用 yield 的。
然后通过遍历器对象的 next 方法,使指针从函数头部向下移一个状态。直到遇到下一个 yield 语句。
Generator 函数是分段执行的,yield 语句是暂停执行的标记,而 next 方法可以恢复执行。
1 | hw.next(); |
next 方法的参数
yield 句本身没有返回值,或者说总是返回 undefined。next 方法可以带一个参数,该参数就会被当作上一个 yield 语句的返回值。
co
Generator 经常被用做顺序执行异步流程。
但 next 函数要一次次的写,很烦,于是 有了各种方案。
- Thunk
- co
co 函数接收一个 generator 为参数,然后就会自动执行 generator。
同时,co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数。
## Async Functions
Async Fuctions 其实只是 Generator 的语法糖,外带一个类 co 的自动执行器。
1 | var gen = function* (){ |
- 语法上,将 * 换成了 async,yield 换成了 await。
- 语义上更清晰,一看就知道这是一个异步函数。需要 await 等待结果。
- 内置执行器,不用依赖 co。
- 返回值是Promise。
## 常用库的 Promise 版
- HTTP Request https://github.com/request/request-promise
- MySQL https://github.com/mysqljs/mysql/
- node-promise-mysql https://github.com/lukeb-uk/node-promise-mysql
- node-mysql-promise https://github.com/martinj/node-mysql-promise