告别回调噩梦,从这里开始
express
请看下面来自官网的代码和执行顺序:koa
以上代码的实现若是用回调函数来实现,无疑是一场噩梦,而KOA却以十分优雅的方式实现了以下图洋葱图通常的回调:函数
核心是利用ES6的新特性:generatorcode
具体实现是利用KOA的两个NIUBI轰轰的模块:compose和CO中间件
compose模块,用于将全部generator中间件串联起来,基本上就是将后一个generator赋给前一个generator的next参数。也就是在yield后面调用下一个generate函数。
大体原理:对象
// 中间件 a function* a(next) { yield 1; // 执行下一个中间件 yield* next; yield '继续执行A中间件'; } // 中间件 b function* b(next) { yield 2; yield 3; } var next = function* (){}; var i = [a, b].length; // 经过next首尾相连 while(i--) { next = [a, b][i].call(null, next); } // 包裹第一个middleware function* start(ne) { return yield* ne; } // 输出 console.log(start(next).next()); console.log(start(next).next()); console.log(start(next).next()); console.log(start(next).next()); 输出结果: ➜ a-lab ./a { value: 1, done: false } { value: 2, done: false } { value: 3, done: false } { value: '继续执行A中间件', done: false }
这里能够看出来:compose取中间件是作i-循环的,可是因为一开始是吧中间件推入栈中,顺序为FILO,全部顺序是没问题的。blog
可是:那个负责把全部中间件串起来的next其实自己也是一个generator,可是,若是在Generater函数内部,调用另外一个Generator函数,默认状况下是没有效果的。递归
因此这时候就轮到咱们的CO模块出场啦路由
CO模块:CO模块便经过递归使得嵌套好的generate依次自动执行(包装为Promise对象)
大体源码实现generator
function run(gen){ var g; if (typeof gen.next === 'function') { g = gen; } else { g = gen(); } function next(){ var tmp = g.next(); //若是tmp.done为true,那么证实generator执行结束,返回。if (tmp.done) { return; } elseif (typeof g.next === 'function') { run(tmp.value); next(); } } next(); }