koa 是由 tj大神利用 generator 开发的 web 框架。要理解 koa,首先要先了解 generator 与 co。作为搞定 koa 的第一篇,我们便谈谈这个。文章首发在boke.io
系列目录
generator介绍
function* Gene(){
yield 1;
yield 2;
}
var gene = Gene();
console.log(gene.next());//{ value: 1, done: false }
console.log(gene.next());//{ value: 2, done: false }
console.log(gene.next());//{ value: undefined, done: true }
console.log(gene.next());//Error: Generator has already finished 经@Ralph-Wang提醒从 v0.11.13 开始不抛错了,返回{ value: undefined, done: true }
从上面我们可以看到
- generator 的定义和函数类似,只是在 function 后面多了一个*
- 调用generator 和调用函数一样,只是不像函数立即执行,而是会生成一个对象
- generator 生成的对象存在一个 next 函数,调用 next 会返回 yield运算的结果对象,并停止。再次调用会在下一个 yield 处停止。
- 当所有的 yield 被执行完,调用 next 函数会返回{ value: undefined, done: true }。再次调用会报错
generator 与异步
看完 generator 的介绍,你心里回想这跟异步有毛关系?不着急听我接着说
串行请求两个网页的代码
var request = require('request');
var a = {};
var b = {};
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
a.response = response;
a.body = body;
request('http://www.yahoo.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
b.response = response;
b.body = body;
}
});
}
});
我们再看看最终我们是如何利用 generator请求网页的
co(function *(){
var a = yield request('http://google.com');
var b = yield request('http://yahoo.com');
console.log(a[0].statusCode);
console.log(b[0].statusCode);
})()
上面的代码可以看到,co 里面传入了一个 generator,里面用 yield 调用异步函数。从逻辑上看,里面的异步被变成了同步。
co 到底有什么魔法?可以把我们从异步中解救出来?
想想 generator 的特性,当我们执行第一个 next 的时候,会调用第一个 request,此时我们去调用 request 的逻辑,然后把 generator 的实例穿进去。当第一个 request 逻辑完成时,在调用这个 generator 的 next,这样就到了第二个 yield 的逻辑了。当然这需要一些逻辑的封装,也就是 co 了。
根据上面的分析,我们大概可以写出下面的代码
function co(Gene){
//先实例化一下
var gene = Gene();
//如果存在 next 函数
if(gene.next){
var fun = gene.next();//把异步函数返回过来,好继续封装
//fun 处理完,再调用 gene.next()
//...
}
}
从上面的代码可以看出
- yield 后面的内容需要返回一个异步函数,这样我们才可进一步封装异步处理的逻辑。
- fun 需要可以传入参数,这样才可以处理多个异步
- 需要一个递归调用,这样才可以持续调用 next,同时根据 next 返回对象中的done属性停止逻辑
- 需要考虑错误处理
今天就到这里,下一篇详细讲一下 co 的源码
参考资料
解决回调金字塔! Harmony Generator, yield, ES6, co框架学习
联系我
node 0.11.14.
function* Gene(){
yield 1;
yield 2;
}
var gene = Gene();
console.log(gene.next());//{ value: 1, done: false }
console.log(gene.next());//{ value: 2, done: false }
console.log(gene.next());//{ value: undefined, done: true }
console.log(gene.next());//{ value: undefined, done: true }
@Ralph-Wang 感谢提醒 不再报错了。。我的版本是v0.11.11
@demohi 嗯, 我又跑去试了=m= … 从 v0.11.13 开始不抛错的
@Ralph-Wang 好敬业 我改一下
@demohi QA 的职业病 =,=
mark