koajs readme里的示例代码,地址 https://github.com/koajs/koa
其中像app.use(function *(next){})
中*
的作用是什么?这样写有什么好处?
var koa = require('koa');
var app = koa();
// logger
app.use(function *(next){
var start = new Date;
yield next;
var ms = new Date - start;
console.log('%s %s - %s', this.method, this.url, ms);
});
// response
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
注:以下代码示例均需要 node.js v0.11.7+ 带
--harmony
参数才能运行。这是ES6的新feature,
function
后面带*
的叫做generator。在generator内部你可以使用
yield
语句:当你调用一个generator函数的时候,你会获得一个iterator对象。
这个对象有一个方法叫做
next()
。每当你调用next()
的时候,generator函数内部就会执行直到遇到下一个yield
语句,然后暂停在那里,并返回一个对象。这个对象含有被yield
的值和generator函数的运行状态。可以看到,只输出了
'step 1'
。这意味着直到你运行下一次next()
之前,generator内部的状态处于暂停之中,但是却不影响generator外部的代码继续运行。直到generator函数内部不再有
yield
语句存在了,这时你再调用next()
,获得的就会是该函数的常规返回值 (return
的值):同时,iterator对象的
next()
方法是可以传递一个参数的。这个参数将会成为generator函数内对应yield
语句的返回值:虽然本意是用来提供一个可循环对象,但可以看到,generator函数可以借助
yield
在需要的时候才继续执行剩余的语句,并且传递回一个值。这让你想到了什么?没错,回调函数!更关键的是,借助generator我们可以用同步的逻辑来表达异步的流程,而不需要嵌套回调。我们只需要对创建iterator对象、调用next()
以及外部函数做一些适当的封装和修改,就可以获得无回调的异步流程控制。这个理念由TJ大神(同时也是 Koa 的作者)在 co 这个库里实现了,而 Koa 本身也是基于 co 来封装中间件函数(每一个中间件函数都是generator)。co 的实现其实不过300行代码,但是包含了很精髓的一些东西,值得细看。