mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 18:32:22 +00:00
add docs/generator
This commit is contained in:
parent
b7d71e98fb
commit
0b0c46c07d
@ -6,7 +6,7 @@
|
||||
|
||||
ES6的generator函数有两个特征。一是,function关键字后面有一个星号;二是,函数体内部使用yield语句,定义遍历器的每个成员(即不同的内部状态)。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
function* helloWorldGenerator() {
|
||||
yield 'hello';
|
||||
@ -15,13 +15,13 @@ function* helloWorldGenerator() {
|
||||
|
||||
var hw = helloWorldGenerator();
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
上面代码定义了一个generator函数helloWorldGenerator,它的遍历器有两个成员“hello”和“world”。调用这个函数,就会得到遍历器。
|
||||
|
||||
当调用generator函数的时候,该函数并不执行,而是返回一个遍历器(可以理解成暂停执行)。以后,每次调用这个遍历器的next方法,就从函数体的头部或者上一次停下来的地方开始执行(可以理解成恢复执行),直到遇到下一个yield语句为止。也就是说,next方法就是在遍历yield语句定义的内部状态。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
hw.next()
|
||||
// { value: 'hello', done: false }
|
||||
@ -36,17 +36,25 @@ hw.next()
|
||||
// Error: Generator has already finished
|
||||
// ...
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
上面代码一共调用了四次next方法。
|
||||
|
||||
- 第一次调用:函数开始执行,直到遇到第一句yield语句为止。next方法返回一个对象,它的value属性就是当前yield语句的值hello,done属性的值false,表示遍历还没有结束。
|
||||
- 第一次调用
|
||||
|
||||
- 第二次调用:函数从上次yield语句停下的地方,一直执行到下一个yield语句。next方法返回的对象的value属性就是当前yield语句的值world,done属性的值false,表示遍历还没有结束。
|
||||
函数开始执行,直到遇到第一句yield语句为止。next方法返回一个对象,它的value属性就是当前yield语句的值hello,done属性的值false,表示遍历还没有结束。
|
||||
|
||||
- 第三次调用:函数从上次yield语句停下的地方,一直执行到函数结束。next方法返回的对象的value属性就是函数最后的返回值,由于上例的函数没有return语句(即没有返回值),所以value属性的值为undefined,done属性的值true,表示遍历已经结束。
|
||||
- 第二次调用
|
||||
|
||||
- 第四次调用:由于此时函数已经运行完毕,next方法直接抛出一个错误。
|
||||
函数从上次yield语句停下的地方,一直执行到下一个yield语句。next方法返回的对象的value属性就是当前yield语句的值world,done属性的值false,表示遍历还没有结束。
|
||||
|
||||
- 第三次调用
|
||||
|
||||
函数从上次yield语句停下的地方,一直执行到函数结束。next方法返回的对象的value属性就是函数最后的返回值,由于上例的函数没有return语句(即没有返回值),所以value属性的值为undefined,done属性的值true,表示遍历已经结束。
|
||||
|
||||
- 第四次调用
|
||||
|
||||
由于此时函数已经运行完毕,next方法直接抛出一个错误。
|
||||
|
||||
Generator函数使用iterator接口,每次调用next方法的返回值,就是一个标准的iterator返回值:有着value和done两个属性的对象。其中,value是yield语句后面那个表达式的值,done是一个布尔值,表示是否遍历结束。
|
||||
|
||||
@ -58,7 +66,7 @@ yield语句与return语句有点像,都能返回紧跟在语句后面的那个
|
||||
|
||||
yield语句本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
function* f() {
|
||||
for(var i=0; true; i++) {
|
||||
@ -73,7 +81,7 @@ g.next() // { value: 0, done: false }
|
||||
g.next() // { value: 1, done: false }
|
||||
g.next(true) // { value: 0, done: false }
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
上面代码先定义了一个可以无限运行的generator函数f,如果next方法没有参数,每次运行到yield语句,变量reset的值总是undefined。当next方法带一个参数true时,当前的变量reset就被重置为这个参数(即true),因此i会等于-1,下一轮循环就会从-1开始递增。
|
||||
|
||||
@ -81,7 +89,7 @@ g.next(true) // { value: 0, done: false }
|
||||
|
||||
generator函数的这种暂停执行的效果,意味着可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield语句下面,反正要等到调用next方法时再执行。所以,generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
function* loadUI() {
|
||||
showLoadingScreen();
|
||||
@ -95,13 +103,13 @@ loadUI.next()
|
||||
// 卸载UI
|
||||
loadUI.next()
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
上面代码表示,第一次调用loadUI函数时,该函数不会执行,仅返回一个遍历器。下一次对该遍历器调用next方法,则会显示登录窗口,并且异步加载数据。再一次使用next方法,则会隐藏登录窗口。可以看到,这种写法的好处是所有登录窗口的逻辑,都被封装在一个函数,按部就班非常清晰。
|
||||
|
||||
注意,yield语句是同步运行,不是异步运行(否则就失去了取代回调函数的设计目的了)。实际操作中,一般让yield语句返回Promises对象。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
var Q = require('q');
|
||||
|
||||
@ -115,7 +123,7 @@ function *f(){
|
||||
yield delay(100);
|
||||
};
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
上面代码使用Promise的函数库Q,yield语句返回的就是一个Promise对象。
|
||||
|
||||
@ -125,7 +133,7 @@ for...of循环可以自动遍历Generator函数,且此时不再需要调用nex
|
||||
|
||||
下面是一个利用generator函数和for...of循环,实现斐波那契数列的例子。
|
||||
|
||||
{% highlight javascript %}
|
||||
```javascript
|
||||
|
||||
function* fibonacci() {
|
||||
let [prev, curr] = [0, 1];
|
||||
@ -140,8 +148,6 @@ for (n of fibonacci()) {
|
||||
console.log(n);
|
||||
}
|
||||
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
从上面代码可见,使用for...of语句时不需要使用next方法。
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user