生成器

  • generator通过function* 进行定义,并且除了return语句,还可以使用yield进行返回数据;
1
2
3
4
5
6
7
8
9
10
11
12
13
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
  • 调用生成器方法,生成对应的生成器。如果需要通过生成器生成值,则需要调用对应的生成方法;
1
2
3
4
5
6
7
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}

通过调用next()执行生成器,当生成器执行到yield语句时,就会返回一个对象给next()函数,然后生成器进入暂停的状态;

此时的对象,value属性是yield语句返回的值,done属性表示生成器是否已经结束了;

for..of遍历生成器

1
2
3
for (var x of fib(10)) {
console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}

保存函数状态

生成器拥有对象才具有的特性:保存函数的状态;

同样是生成序列,使用对象的方式进行生成;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};

协程同步效果

生成器能让我们实现协程的效果,让异步代码看起来像同步的一样;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});

通过生成器改写成同步代码的形式:

1
2
3
4
5
6
7
8
9
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}