1. generator
es6有一个新功能特性,叫generator,它是解决回调地狱的一个生成器。
众所周知,nodejs的一大特性就是可以利用异步回调,它是优点,但也带来了回调噩梦。
有很多方法可以解决和减少回调嵌套太深的问题,比如promise, async,但都解决得不太彻底。
generator才是真正解决这类问题的利器,而本节所讲的koa框架也是基于generator。
要写一个generator函数很简单,我们先来看一个简单的函数。
var hello = function(name) {
return 'hello ' + name;
}
console.log(hello('James'));
使用node --harmony example.js
执行这个脚本。
将输出:
hello James
要改写成generator,很简单,只需要加一个*
,如下:
var hello = function *(name) {
return 'hello ' + name;
}
console.log(hello('James'));
终端将输出:
{}
现在还不行,再来改写一下。我们使用了next
关键字。
var hello = function *(name) {
return 'hello ' + name;
}
var gen = hello('James');
console.log(gen.next());
这个终端输出了我们要的效果:
{ value: 'hello James', done: true }
之前返回的是空对象{}
,现在有值了。
value
代表返回的值,done
代表这个generator是不是已经完成终止了。
什么意思?generator还有状态?
有的,它可以被暂停,重新运行,可以终止。
我们来试下它是如何被暂停的,这个时候得用yield
关键字。
var hello = function *(name) {
yield 'my name is ' + name;
return 'hello ' + name;
}
var gen = hello('James');
console.log(gen.next());
终端输出:
{ value: 'my name is James', done: false }
done: false
表示还没真正终止,停在了yield
关键字所在的那一行。
要让它真正终止,得再调用一次next
命令。
var hello = function *(name) {
yield 'my name is ' + name;
return 'hello ' + name;
}
var gen = hello('James');
console.log(gen.next());
console.log(gen.next());
输出:
{ value: 'my name is James', done: false }
{ value: 'hello James', done: true }
要调用两次next
程序才最终停止。
下面给一个更直观的例子让你感受一下generator。
// 代码来源于https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
function* idMaker(){
var index = 0;
while(index < 3)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
说了这么多,你可能会觉得,这个有什么用啊,能解决异步回调的问题?
能的,它的神奇在于yield那个命令,你可以写很多行这样的命令,后面接的是异步任务。
比如:
function* gen(){
var result;
result = yield fetch('a');
console.log(result);
result = yield fetch('b');
console.log(result);
result = yield fetch('c');
console.log(result);
}
2. koa
next generation web framework for node.js
koa是下一代的nodejs web框架。以前比较流行的是express框架,现在好多人研究这个,express的主要开发者现在都转向于koa的开发了。
本节所讲的koa是第一版本的,如果要使用第二版本的,只是语法变了,思想却是不变的
我们先来感受一下koa。
先来安装。
$ npm install koa
创建app.js文件,内容如下:
var koa = require('koa');
var app = koa();
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
使用node app.js
运行这个文件,浏览器将输出Hello World
。
这个没什么,只是输出一行简单的文本。
我们再来看一个例子,是官方列出的。
// 代码来源于https://code.tutsplus.com/tutorials/introduction-to-generators-koajs-part-1--cms-21615
var koa = require('koa')();
koa.use(function* (next) {
//do something before yielding/passing to next generator function in line which will be 1st event in downstream
console.log("A");
yield next;
// do something when the execution returns upstream, this will be last event in upstream
console.log("B");
});
koa.use(function* (next) {
// do something before yielding/passing to the next generator function in line, this shall be 2nd event downstream
console.log("C");
yield next;
// do something when the execution returns upstream and this would be 2nd event upstream
console.log("D");
});
koa.use(function* () { // do something before yielding/passing to next generator function in line. Here it would be last function downstream
console.log("E");
this.body = "hey guys";
console.log("F"); // First event of upstream (from the last to first)
});
koa.listen(3000);
它将输出:
A
C
E
F
D
B
为什么会是这样呢,这跟generator有关。
要理解这个,先来理解一下koa的特性。
开发koa,你会觉得你在写middleware,这个东西有点像ruby的rack middleware
。
它的中文名可以译成中间件
。
ruby的中间件是这样的,它传入一个环境变量(env),经过中间件的处理,返回一个数组,数组内容是[status, headers, body]。
分别是状态码,响应头信息,内容体。
一个中间件处理完之后,并不直接返回,而是把它的结果交给下一个中间件,直接全部处理结束,才返回。
它有点像一坐桥,连接桥头和桥尾两端,然后像koa应用是由很多这样的桥组成。
它是用中间件来组合而成一个应用。
koa.use
里面的就可以理解为一个中间件。
这样有什么好处呢?
好处多着呢,比如可以统一处理一些事情,比如cache,日志输出,不然没有中间件,你要处理这样的东西,或许只能在应用中,一行行地改,而有了中间件,它在中间拦截处理了,很方便,特别有意思的是,koa应用可以作为一个中间件应用包在一个express应用中,要开发koa的中间件也很简单,使用别人开发好的,一拿来就能用,超级方便。
现在回头来看上面那个代码,为什么是那样输出呢?
你得理解yield
这个指令,它会暂停你的中间件,会执行权交给下一个中间件,等下个中间件执行完,才会最终执行yield
之后的命令。所以最后输出的是B
。
koa之路还很长,好好研究吧。
完结。
嗯, 楼主再深入研究研究, 学习的精神总是值得肯定的!
最后一段话 是next的功能 不是yield