1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-29 13:52:22 +00:00

修改generator

This commit is contained in:
Ruan Yifeng 2014-12-18 22:24:14 +08:00
parent 4cf70a17ab
commit e635b182f6
2 changed files with 67 additions and 22 deletions

View File

@ -2,15 +2,15 @@
## 含义 ## 含义
所谓Generator简单说,就是一个内部状态的遍历器即每调用一次遍历器内部状态发生一次改变可以理解成发生某些事件。ES6引入Generator函数作用就是可以完全控制内部状态的变化依次遍历这些状态。 所谓Generator有多种理解角度。首先,可以把它理解成一个内部状态的遍历器即每调用一次遍历器内部状态发生一次改变可以理解成发生某些事件。ES6引入Generator函数作用就是可以完全控制内部状态的变化依次遍历这些状态。
Generator函数就是普通函数但是有两个特征。一是function关键字后面有一个星号二是函数体内部使用yield语句定义遍历器的每个成员即不同的内部状态yield语句在英语里的意思就是“产出” 在形式上,Generator是一个普通函数但是有两个特征。一是function命令与函数名之间有一个星号二是函数体内部使用yield语句定义遍历器的每个成员即不同的内部状态yield语句在英语里的意思就是“产出”
```javascript ```javascript
function* helloWorldGenerator() { function* helloWorldGenerator() {
yield 'hello'; yield 'hello';
yield 'world'; yield 'world';
return 'ending'; return 'ending';
} }
@ -50,9 +50,7 @@ hw.next()
总结一下Generator函数使用iterator接口每次调用next方法的返回值就是一个标准的iterator返回值有着value和done两个属性的对象。其中value是yield语句后面那个表达式的值done是一个布尔值表示是否遍历结束。 总结一下Generator函数使用iterator接口每次调用next方法的返回值就是一个标准的iterator返回值有着value和done两个属性的对象。其中value是yield语句后面那个表达式的值done是一个布尔值表示是否遍历结束。
Generator函数的本质其实是提供一种可以暂停执行的函数。yield语句就是暂停标志next方法遇到yield就会暂停执行后面的操作并将紧跟在yield后面的那个表达式的值作为返回对象的value属性的值。当下一次调用next方法时再继续往下执行直到遇到下一个yield语句。如果没有再遇到新的yield语句就一直运行到函数结束将return语句后面的表达式的值作为value属性的值如果该函数没有return语句则value属性的值为undefined。 由于Generator函数返回的遍历器只有调用next方法才会遍历下一个成员所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志next方法遇到yield就会暂停执行后面的操作并将紧跟在yield后面的那个表达式的值作为返回对象的value属性的值。当下一次调用next方法时再继续往下执行直到遇到下一个yield语句。如果没有再遇到新的yield语句就一直运行到函数结束将return语句后面的表达式的值作为value属性的值如果该函数没有return语句则value属性的值为undefined。另一方面由于yield后面的表达式直到调用next方法时才会执行因此等于为JavaScript提供了手动的“惰性求值”Lazy Evaluation的语法功能。
由于yield后面的表达式直到调用next方法时才会执行因此等于为JavaScript提供了手动的“惰性求值”Lazy Evaluation的语法功能。
yield语句与return语句有点像都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield函数暂停执行下一次再从该位置继续向后执行而return语句不具备位置记忆的功能。 yield语句与return语句有点像都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield函数暂停执行下一次再从该位置继续向后执行而return语句不具备位置记忆的功能。
@ -72,7 +70,7 @@ setTimeout(function () {
``` ```
上面代码中只有调用next方法时函数f才会执行。 上面代码中,函数f如果是普通函数在为generator变量赋值时就会执行。但是函数f是一个Generator函数就变成只有调用next方法时函数f才会执行。
利用Generator函数可以在任意对象上部署iterator接口。 利用Generator函数可以在任意对象上部署iterator接口。
@ -97,7 +95,7 @@ for (let [key, value] of iterEntries(myObj)) {
``` ```
上述代码中,由于Generator函数返回一个具有iterator接口的对象所以只要让yield语句每次返回一个参数对象的成员可以在任意对象上部署next方法。 上述代码中,myObj是一个普通对象通过iterEntries函数就有了iterator接口。也就是说可以在任意对象上部署next方法。
## next方法的参数 ## next方法的参数
@ -234,8 +232,8 @@ function scheduler(task) {
setTimeout(function () { setTimeout(function () {
if (!task.next().done) { if (!task.next().done) {
scheduler(task); scheduler(task);
} }
}, 0); }, 0);
} }
``` ```
@ -247,13 +245,13 @@ function scheduler(task) {
var Q = require('q'); var Q = require('q');
function delay(milliseconds) { function delay(milliseconds) {
var deferred = Q.defer(); var deferred = Q.defer();
setTimeout(deferred.resolve, milliseconds); setTimeout(deferred.resolve, milliseconds);
return deferred.promise; return deferred.promise;
} }
function* f(){ function* f(){
yield delay(100); yield delay(100);
}; };
``` ```
@ -267,16 +265,16 @@ for...of循环可以自动遍历Generator函数且此时不再需要调用nex
```javascript ```javascript
function *foo() { function *foo() {
yield 1; yield 1;
yield 2; yield 2;
yield 3; yield 3;
yield 4; yield 4;
yield 5; yield 5;
return 6; return 6;
} }
for (let v of foo()) { for (let v of foo()) {
console.log(v); console.log(v);
} }
// 1 2 3 4 5 // 1 2 3 4 5
@ -305,6 +303,52 @@ for (let n of fibonacci()) {
从上面代码可见使用for...of语句时不需要使用next方法。 从上面代码可见使用for...of语句时不需要使用next方法。
## 作为数据结构的Generator
Generator可以暂停函数执行返回任意表达式的值。这种特点使得Generator有多种应用场景。
- 异步操作的同步化表达abstractions of async behavior
- 控制流管理control flow management
- 数据结构data structure)
第一种和第二种应用在本章前面部分已经有所提及了。这里主要再补充一下Generator可以看作是数据结构因为它可以对任意表达式提供类似数组的接口。
```javascript
function *doStuff() {
yield fs.readFile.bind(null, 'hello.txt');
yield fs.readFile.bind(null, 'world.txt');
yield fs.readFile.bind(null, 'and-such.txt');
}
```
上面代码就是依次返回三个函数但是由于使用了Generator函数导致可以像处理数组那样处理这三个返回的函数。
```javascript
for (task of doStuff()) {
// task是一个函数可以像回调函数那样使用它
}
```
实际上如果用ES5表达完全可以用数组模拟Generator的这种用法。
```javascript
function doStuff() {
return [
fs.readFile.bind(null, 'hello.txt'),
fs.readFile.bind(null, 'world.txt'),
fs.readFile.bind(null, 'and-such.txt')
];
}
```
上面的函数可以用一模一样的for...of循环处理两相一比较就不难看出Generator的这种用法就是让数据或者操作可以像数组那样处理。
## throw方法 ## throw方法
Generator函数还有一个特点它可以在函数体外抛出错误然后在函数体内捕获。 Generator函数还有一个特点它可以在函数体外抛出错误然后在函数体内捕获。

View File

@ -45,6 +45,7 @@
- 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方法时不能带有参数 - 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](http://davidwalsh.name/es6-generators): 由浅入深探讨Generator的系列文章共四篇 - Kyle Simpson, [ES6 Generators: Complete Series](http://davidwalsh.name/es6-generators): 由浅入深探讨Generator的系列文章共四篇
- Gajus Kuizinas, [The Definitive Guide to the JavaScript Generators](http://gajus.com/blog/2/the-definetive-guide-to-the-javascript-generators): 对Generator的综合介绍 - Gajus Kuizinas, [The Definitive Guide to the JavaScript Generators](http://gajus.com/blog/2/the-definetive-guide-to-the-javascript-generators): 对Generator的综合介绍
- Jan Krems, [Generators Are Like Arrays](https://gist.github.com/jkrems/04a2b34fb9893e4c2b5c): 讨论Generator可以被当作数据结构看待
## Promise对象 ## Promise对象