Generator 是一种控制程序迭代的方法,让顺序执行的迭代程序变成异步执行 (此异步和 Node.js 的异步调用有差异) 。在 Node.js 里,它的存在目的就是可以写出更好的控制流。

如果需要扩展这个代码,增加更多的回调:

从例子可以看到,generator 和一般的函数并没有太大的区别,仅仅需要在 function 后加一个星号即可,而最大差别是,函数是直接调用并返回结果,而 generator 则是调用后,创建并返回一个 constructor 为 GeneratorFunctionPrototype 的对象,然后通过它的 next 方法来让函数执行并获取 yield 语句的值:

yield 关键字是 generator 的核心,当 next 被调用时,将会执行 generator 内的代码,一旦遇到 yield 时将停止执行,并等待下一个 next 的调用,不停重复,直到所有的代码执行完毕。这赋予了函数异步执行的能力。

done 标记是否所有代码已执行完毕。

经过 bluebird.promisifyAll 处理的对象的所有函数将被封装成 Promise 模式,封装后的函数一般会在函数名后面增加 Async,如 fs.readdirAsync。

经过这两步处理,readFiles 就可以改造成如下所示 (为了缩减代码行数,移除了过滤功能) :

经过这样的处理后,readFiles 少了一些多余的嵌套,又保留了该有的异步能力。

Generator 的概念其实就是惰性求值,通过暂停函数执行来让开发者控制程序的控制流,而不是像及早求值那样,语句到那里了就需要立刻求出值。

Generator 并不是用来代替别的控制流的灵丹妙药,它只是一种可能性,让你写出更好的代码的可能性,Koa 的官方例子就很好地解释了这一点:

CommonMark,最早的名字叫 Standard Markdown,后来迫于 Markdown 原作者 John Gruber 的压力而改名。 虽然这已经是今年九月初的事情了,而且我在当时就已经表达了我的看法,但还是完整说说我的观点。