1.Koa1 内置 Co模块。
2.调用koa的use方法的时候,koa会把接收到的 Generator函数加入到koa实例的 middleware数组中。
3.调用koa的callback方法时,koa会在内部调用Co的wrap方法,把所有的Generator函数包装成Promise,并自动执行所有的Generator函数,并通过Generator的next()函数把value返回。
示例代码:
function *(){
const client = yield clientService.create(params.channel, params.username);//一个异步操作。Co模块会把异步请求的结果赋值给 client
console.log(client);
}
### app.js
const http = require('http');
const koa = require('koa');
const app = koa();
app.use(Generator functions);
/**
* 创建一个HTTP服务器
*/
var server = http.createServer(app.callback());
### Koa.js 源码
app.use = function(fn){
/**
* 这里将所有 app.js中 app.use(fn)的fn加入到koa实例的 middleware中。
*/
this.middleware.push(fn);
return this;
}
app.callback = function(){
const fn = co.wrap(compose(this.middleware)); //调用co.wrap(fn)方法,得到一个Promise函数作为返回值。
return function handleRequest(req, res){
var ctx = self.createContext(req, res);
//ctx会执行这个返回的fn <也就是Co.js中 的createPromise 函数,该函数会执行co(gen)函数,并把前面app.use()传递的所有函数都放进去>
fn.call(ctx).then(function handleResponse() {
respond.call(ctx);
}).catch(ctx.onerror);
}
}
### Co.js
co.wrap = function (fn) {
createPromise.__generatorFunction__ = fn;
return createPromise; //返回一个Promise函数
function createPromise() {
return co.call(this, fn.apply(this, arguments));
}
};
function co(gen) {
const ctx = this;
return new Promise(function(resolve, reject) {
if (typeof gen === 'function')
gen = gen.apply(ctx, []); //执行这些Generator函数
if (!gen || typeof gen.next !== 'function')
return resolve(gen);//如果执行结果中不是Generator函数,则直接返回执行结果。
onFulfilled();
function onFulfilled(res) {
var ret;
try {
//当Generator函数执行过第一次next()以后,res会有值得。{value:{name:'张三'},done:false}
//在下面那个 next()函数中我们可以看到。然后由于next()函数的递归调用,导致第二次执行这里的时候res有值了,
//执行gen.next(res)时会直接跳出这里,并把res<也就是:{name:'张三'}>传递给我们代码中做的赋值,
//上面示例中的:const client = yield clientService.create(params.channel, params.username)。
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
}
function next(ret) {
if (ret.done) //如果这个 Generator函数的yeild执行完了,则返回执行结果的value。
return resolve(ret.value);
//如果没执行完,则将value包装成Promise,继续递归执行。
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value))
return value.then(onFulfilled, onRejected);
}
}
}