前言
了解
co
的前提是已经知晓generator
是什么,可以看软大神的Generator 函数的语法,
co是TJ大神写的能够使generator自动执行的函数库,而我们熟知的koa也用到了它管理异步流程控制,将异步任务书写同步化,爽的飞起,也摆脱了一直以来的回调地狱问题。
如何使用
首先我们根据co的官方文档来稍做改变看下,到底如何使用co,再一步步进行源码分析工作(这篇文章分析的co版本是
4.6.0
)。
yield 后面常见的可以跟的类型
- promises
- array (parallel execution)
- objects (parallel execution)
- generator functions (delegation)
promises
|
|
array
|
|
objects
|
|
generator functions
|
|
最后说一下,关于执行传入的generator函数接收参数的问题
|
|
从co函数的第二个参数开始,便是传入的generator函数可以接收的实参
开始分析源码
你可以把以上代码拷贝至本地测试一番看看效果,接下来我们一步步开始分析co的源码
首先经过上面的例子可以发现,co函数本身接收一个generator函数,并且co执行后返回的是Promise
|
|
在Promise的内部,先执行了外部传入的gen
,执行的结果如果不具备next属性(且要是一个函数),就直接返回,并将执行成功回调resolve(gen)
,否则得到的是一个指针对象。
接下来继续看…
|
|
我觉得可以把 onFulfilled
和 onRejected
看成是返回的Promise的resolve
和reject
。
而onFulfilled
也是将原生的generator生成器的next方法包装了一遍,大概是为了抓取错误吧(看到内部的try catch了吗)
好,我们看到了co内部将指针移动到了第一个位置之后,接着执行了内部的next方法,接下来聚焦在该函数上
|
|
聪明的你,是不是已经明白了co是怎么将异步流程自动管理起来了
但是我对next函数中的toPromise函数还有疑问,他到底做了什么事?使得co(generatorFun)中yield可以支持数组、对象、generator函数等形式。
一步步来看
|
|
首先如果obj不存在,就直接返回,你想啊,co本来就是依赖上一次指针返回的value是Promise或者其他,这个时候如果返回
|
|
那就没有必要再给一个false值转成Promise形式了吧。
接着,如果obj本身就是个Promise也是直接返回,用了内部的isPromise函数进行判断,我们看下他怎么实现的。
|
|
其实就是判断了obj的then属性是不是个函数
再接着,如果是个generator函数或者generator生成器,那就像你自己调用co函数一样,手动传到co里面去执行。
isGeneratorFunction
|
|
通过obj的constructor属性去判断其是否属于GeneratorFunction
,最后如果constructor属性没判断出来,再去用isGenerator,判断obj的原型是不是generator生成器
|
|
判断的条件也比较直接,需要符合两个条件,一个是obj.next要是一个函数,一个是obj.throw要是一个函数
接下来继续看
如果obj既不是Promise,也不是isGeneratorFunction和isGenerator,要是一个普通的函数,就将该函数包装成Promise的形式,这里我们主要需要看thunkToPromise
|
|
接下来是重头戏了,co中如果处理yield后面跟一个数组呢?主要是arrayToPromise函数的作用
|
|
还有最后一个判断,如果obj是个对象怎么办?
|
|
结尾
到这里,co源码分析就告一段落了。总感觉有些没有说到位,欢迎大家拍砖,晚安。