摘要本系列文章是关于Koa框架的,目前重点版本为Koav1。主要分为以下几个方面:Koa源码分析(一)——generatorKoa源码分析(二)——co实现Koa源码分析(三)——中间件机制实现Genetator函数Generator函数是提供的一个异步函数通过ES6一种编程解决方案,其语法行为与传统函数完全不同。细细分析,我们可以看到阮一峰老师的《ECMAScript 6 入门 --- Generator》语法的两大特点。function关键字和函数名之间的*函数体使用了里面的yield语句。我们定义一个generatorFunction示例:function*firstGenerator(){varone=yield'one';控制台日志(一);vartwo=yield'two';concole.log(二);varthird=yield'third';控制台日志(第三);return'over'}用*表示的函数声明firstGenerator函数是一个生成器函数。函数中的yield关键字可以理解为在当前位置设置断点。如果对此有疑问,请参考后续。句法行为那么生成器函数的语法行为与传统函数有何不同呢?下面我们来梳理一下生成器函数的操作步骤。varit=firstGenerator();console.log(it.next(1));//{value:"one",done:false}console.log(it.next(2));//{value:"two",done:false}console.log(it.next(3));//{value:"third",done:false}console.log(it.next(4));//{value:"over",done:true}首先,通过执行firstGenerator函数,我们可以得到一个生成器对象it,它是一个迭代器对象。此时,firstGenerator函数并没有被执行,而是返回了iterator对象。我们可以通过it对象中的next方法触发firstGenerator函数开始执行。这时,我们调用它.next(1)。请注意,next注入的参数1没有任何作用。当firstGenerator函数执行到yield语句时,打断点,停留在这里,yield之后的变量传递给it.next(1)结果对象中的value字段。此外,done字段表示firstGenerator函数尚未完成。执行完之后,还是停留在断点处。同时,将执行权交换给it.next(1)。第二次执行it.next(2),执行权再次交给firstGenerator函数,将next带入的参数传递给函数中的变量one,此时输出2。运行到yield'two'语句时,再次将执行权归还it.next(2),传值。第三次执行it.next(3)的过程和第二次完全一样。最后一次执行it.next(4)时,在此之前,firstGenerator函数断点在varthird=yield'third',当it.next(4)将执行权交给firstGenerator函数时,4是传递给变量third,此刻输出4。当return语句执行时,整个函数已经执行完毕,将'over'传递给it.next(4)返回的结果中的value字段,done字段为true。如果没有return语句,则value字段返回null。这样就执行了整个firstGenerator函数。我们可以将Generator函数比作一只懒惰的蟾蜍。每次需要用it.next()方法戳一下,都会有相应的动作。如果你了解python中协程的概念,你应该对Generator函数的语法行为有很好的理解。高级语法在Generator函数中yield的语法中,其背后的值也可以是函数、对象等。yield后面可以跟另一个Generator对象。function*subGen(){console.log('stepinsubgenerator');varb=yield'sub1';控制台日志(b);console.log('stepoutsubgenerator');}varsubGenerator=newsubGen();function*mainGen(){vara=yield'main1';控制台日志(一);varb=yield*subGenerator;控制台日志(b);varc=yield'main2';控制台日志(c);return'over';}varit=mainGen();console.log(it.next(1));//{value:'main1',done:false}console.log(it.next(2));//2//进入子生成器//{value:'sub1',done:false}console.log(it.next(3));//3//退出子生成器//null//{value:'main2',done:false}console.log(it.next(4));//4//{value:'over',done:true}yield后跟*subGenerator对象,等价到断点进入subGenerator的subGen,等待所有subGen执行完再返回继续执行,类似于递归。说白了就是把subGen嵌入到mainGen中。subGen函数中的return语句不作为断点。结束语Generator函数是ES6的新特性,可以很好的解决JavaScript中的魔鬼回调问题。Koa框架利用这个特性很好地组织了异步代码的结构。
