Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

koa源码分析系列(一)generator #7

Open
purplebamboo opened this issue Jul 11, 2017 · 1 comment
Open

koa源码分析系列(一)generator #7

purplebamboo opened this issue Jul 11, 2017 · 1 comment

Comments

@purplebamboo
Copy link
Owner

koa源码分析系列(一)generator

koa基于co实现,co又是使用了es6的generator特性,所以,没错这个特性支持很一般。
有下面几种办法体验generator:

  • node v0.11 可以使用 (node —harmony)
  • 使用gnode来使用,不过据说性能一般
  • 使用chrome体验,打开chrome://flags/, 搜索harmony, 启用,重启chrome即可。

##generator的es6规范。

什么是generator?generator是javascript1.7的内容,是 ECMA-262 在第六个版本,即我们说的 Harmony 中所提出的新特性。

首先我们先定义一个generatorFunction:

function* start() {
  var a = yield 'start';
  console.log(a);
  var b = yield 'running';
  console.log(b);
  var c = yield 'end';
  console.log(c);
  return 'over';
}
console.log(start.constructor.name) //"GeneratorFunction"

带有 *的函数声明即代表是一个GeneratorFunction,GeneratorFunction里面可以使用yield关键字,可以理解为在当前位置设置断点。

下面我们获得一个generator并且使用它

var it = start();
console.log(it.next());//Object {value: "start", done: false}
console.log(it.next(22));//22  object {value: 'running', done: false}
console.log(it.next(333));//333 Object {value: 'end', done: false}
console.log(it.next(444));//444 Object {value: "over", done: true}

通过执行GeneratorFunction我们可以得到一个generator对象也就是it。it对象有一个next方法。
当我们执行start()的时候,start里面的代码并没有执行。当我们第一次调用it.next()的时候代码会执行到第一个yield声明的地方。也就是var a = yield 'start';,注意这边只是执行到了赋值语句的右边yield部分,换句话说var a =这个赋值语句还没有执行。
此时it.next()返回的是一个对象,value是yield语句的值,这个值可以是字符串,函数,对象等等等,done代表当前的GeneratorFunction是否执行完毕。

也许你注意到了我们后来调用了it.next(22)给next传了一个参数。这个时候var a =赋值语句开始执行,实际上此时yield 'start'返回的就是22,也就是我们传的参数。一直执行到yield 'running';代码再次断点停住了。next方法的参数会成为上一个yield的返回值。

最后当执行到return 'over';的时候,next(444)返回的对象的done为true,代表整个代码执行完毕。

es6的generator的规范可以点这里,可惜由于本身generator还没有正式定稿,所以一直在修改中.前面的wiki也没有更新。目前来说wiki里面提到的send和close方法都已经移除了。变更记录可以在v8的issue里找到。https://code.google.com/p/v8/issues/detail?id=2715

##进阶知识:generator的Delegating yield
Delegating yield是generator的进阶内容。代表一个代理的yield。
前面提到yield后面的值可以是函数,对象,等等。其实yield后面还可以这么用。

function* run() {
console.log("step in child generator")
var b = yield 'running';
console.log(b);
console.log("step out child generator")

}
var runGenerator = run();
function* start() {
  var a = yield 'start';
  console.log(a);
  yield *runGenerator;
  var c = yield 'end';
  console.log(c);
  return 'over';
}
var it = start();
console.log(it.next());//Object {value: "start", done: false}
console.log(it.next(22));//22 step in child generator  object {value: 'running', done: false}
console.log(it.next(333));//333 step out child generator  Object {value: 'end', done: false}
console.log(it.next(444));//444 Object {value: "over", done: true}

yield后面可以跟 *anothergenerator,这样当前的断点就会进入到anothergenerator的generatorfunction里面,等子generator全部执行完后再回来继续执行。这个其实有点类似递归的意思。

其实说白了上面的代码跟之前的是等价的。yield*generator其实相当于把子generator的generatorfunction的代码混入了进来。

另外子generatorfunction的return值会做为yield*generator的返回值。
实例如下:

function* run() {
console.log("step in child generator");
return "child over";
var b = yield 'running';
console.log(b);
console.log("step out child generator")

}
var runGenerator = run();
function* start() {
  var a = yield 'start';
  console.log(a);
  var childValue = yield *runGenerator;
  console.log("childValue=="+childValue);
  var c = yield 'end';
  console.log(c);
  return 'over';
}
var it = start();
console.log(it.next());
//Object {value: "start", done: false}
console.log(it.next(22));
//22
//step in child generator
//childValue==child over
//Object {value: "end", done: false}
console.log(it.next(333));
//333 Object {value: "over", done: true}

简单的测试,子generator的generatorFunction里面如果有return的话,下面的断点就不再起作用,而是提前返回,并且return的值 作为代理调用的返回值。

##结语
generator是es6的一个新特性,支持还不是很好,但是这并不影响它的成名,因为通过它可以很好的解决javascript的“恶魔”回调问题。基本generator的功能都介绍了。通过设置断点,我们将可以很好的将回调解放出来,目前比较知名的就是TJ的co库了,下篇,我将按照co的原理实现异步编程的一个简陋库。

@Dragon-Rider
Copy link

我发现现在大家都好喜欢用issue来写blog,是为了能方便评论吗🌝。
最近在考虑用github搞一个jekyll,不过不知道他们的seo效果怎么样,结果就发现大家都开始在issue写blog了,哈哈哈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants