Abstract
本系列是关于Koa框架的文章,目前关注版本是Koa v1。主要分为以下几个方面:
co
大名鼎鼎的co是什么?它是TJ大神基于ES6的一些新特性开发的异步流程控制库,基于它所开发的koa被视为未来主流的web框架。
koa基于co实现,而co又是使用了ES6的generator和promise特性。如果还不理解,可以查看阮一峰老师的《ECMAScript 6 入门 — Generator》和《ECMAScript 6 入门 — Promise》。目前co升级为4.X版本事,代码进行了一次颇有规模的重构,我们主要关注co(4.X)的实现思路和源码分析。
使用示例
1 | co(function* (){ |
1 | co(function* (){ |
根据co的功能,它作为异步流程控制的作用,自动调用generator对象的next()方法,实现generator函数的运行,并返回最终运行的结果。
如果要涉及到co的实现细节,我们就会存在以下几个疑问:
- 如何依次调用next()方法
- 如何将yield后边运算异步结果返回给对应的变量
- co自身如何返回generator函数最后的return值
接下来我们正对以上问题,分析TJ大神的源码
源码解析
co源码的流程控制
1 | function co(gen) { |
源码分析完了,我们可以把co串行调用generator函数中yield的过程总结如下:
- 进入外围Promise
- 通过入口onFilfilled()方法,将generator函数运行至第一个yield处,执行该yield后边的异步操作,并将结果传入next方法
- 如果next中传入结果的done为true,则返回外围Promise的resolve
- 如果next中传入结果的done为true,则返回value(即yield后边的对象)是否可以转化为内部Promise对象。如无法转化,则抛出错误,返回外围Promise的reject
- 若能转化为Promise对象,将所有内部Promise并行执行,通过then(onFilfilled, onRejected)开始执行
- 在onFilfilled()或者onRejected()内部调用再次调用next()方法,实现串行执行yield,并肩yield后边的对象传递给next(),依次重复。
- 所有yield执行返回,将最后的return值返回给外围Promise的resovle方法,结束co对generator函数的调用
yield后面对象转化为Promise
能够在co中实现generator函数的逐步调用next()方法,转化为内部Promise将至关重要,而源码是如何转化的呢?哪些对象又是能够转化的呢?接下来,我们看下源码。
1 | function toPromise(obj) { |
结合上述分析,我们可以得到,yield后面只能是函数、Promise对象、Generator函数、Generator迭代器对象、数组(元素仅限之前的4类)和Object(对应value仅限定之前的4类)