From 4bba9a0a71c17e0c59b856a15df735ca1a63e44f Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sun, 5 Oct 2014 19:17:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9generator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/generator.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++ docs/reference.md | 1 + 2 files changed, 67 insertions(+) diff --git a/docs/generator.md b/docs/generator.md index 7e035c5..36bd4c0 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -122,6 +122,29 @@ g.next(true) // { value: 0, done: false } 上面代码先定义了一个可以无限运行的Generator函数f,如果next方法没有参数,每次运行到yield语句,变量reset的值总是undefined。当next方法带一个参数true时,当前的变量reset就被重置为这个参数(即true),因此i会等于-1,下一轮循环就会从-1开始递增。 +再看一个例子。 + +```javascript + +function* foo(x) { + var y = 2 * (yield (x + 1)); + var z = yield (y / 3); + return (x + y + z); +} + +var it = foo(5); + +it.next() +// { value:6, done:false } +it.next(12) +// { value:8, done:false } +it.next(13) +// { value:42, done:true } + +``` + +上面代码第一次调用next方法时,返回`x+1`的值6;第二次调用next方法,将上一次yield语句的值设为12,因此y等于24,返回`y / 3`的值8;第三次调用next方法,将上一次yield语句的值设为13,因此z等于13,这时x等于5,y等于24,所以return语句的值等于42。 + 注意,由于next方法的参数表示上一个yield语句的返回值,所以第一次使用next方法时,不能带有参数。V8引擎直接忽略第一次使用next方法时的参数,只有从第二次使用next方法开始,参数才是有效的。 ## 异步操作的应用 @@ -146,6 +169,29 @@ loader.next() 上面代码表示,第一次调用loadUI函数时,该函数不会执行,仅返回一个遍历器。下一次对该遍历器调用next方法,则会显示Loading界面,并且异步加载数据。等到数据加载完成,再一次使用next方法,则会隐藏Loading界面。可以看到,这种写法的好处是所有Loading界面的逻辑,都被封装在一个函数,按部就班非常清晰。 +Ajax是典型的异步操作,通过Generator函数部署Ajax操作,可以用同步的方式表达。 + +```javascript + +function* main() { + var result = yield request("http://some.url"); + var resp = JSON.parse(result); + console.log(resp.value); +} + +function request(url) { + makeAjaxCall(url, function(response){ + it.next(response); + }); +} + +var it = main(); +it.next(); + +``` + +上面代码的main函数,就是通过Ajax操作获取数据。可以看到,除了多了一个yield,它几乎与同步操作的写法完全一样。注意,makeAjaxCall函数中的next方法,必须加上response参数,因为yield语句构成的表达式,本身是没有值的,总是等于undefined。 + 下面是另一个例子,通过Generator函数逐行读取文本文件。 ```javascript @@ -218,6 +264,26 @@ function* f(){ for...of循环可以自动遍历Generator函数,且此时不再需要调用next方法。 +```javascript + +function *foo() { + yield 1; + yield 2; + yield 3; + yield 4; + yield 5; + return 6; +} + +for (var v of foo()) { + console.log(v); +} +// 1 2 3 4 5 + +``` + +上面代码使用for...of循环,依次显示5个yield语句的值。这里需要注意,一旦next方法的返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for...of循环之中。 + 下面是一个利用generator函数和for...of循环,实现斐波那契数列的例子。 ```javascript diff --git a/docs/reference.md b/docs/reference.md index 062ebc8..1d7172b 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -40,6 +40,7 @@ - Marc Harter, [Generators in Node.js: Common Misconceptions and Three Good Use Cases](http://strongloop.com/strongblog/how-to-generators-node-js-yield-use-cases/): 讨论Generator函数的作用 - Axel Rauschmayer, [Iterators and generators in ECMAScript 6](http://www.2ality.com/2013/06/iterators-generators.html): 探讨Iterator和Generator的设计目的 - StackOverflow, [ES6 yield : what happens to the arguments of the first call next()?](http://stackoverflow.com/questions/20977379/es6-yield-what-happens-to-the-arguments-of-the-first-call-next): 第一次使用next方法时不能带有参数 +- Kyle Simpson, [ES6 Generators: Complete Series]: 由浅入深探讨Generator的系列文章,共四篇 ## Promise对象