世界上最伟大的投资就是投资自己的教育

首页JavaScript
随风 · 凡人

es6 的 generator 和 Node.js 的下一代框架 koa

随风发布于1076 次阅读

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 之路还很长,好好研究吧。

完结。

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
喜欢
我的微信官网服务号精品文章订阅号微信视频号
程序员随风
统计信息
    学员: 21311
    视频数量: 1341
    文章数量: 453

© 汕尾市求知科技有限公司 | 专业版网站 | 关于我们 | 在线学员:1155

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top