Generator函数是es6提供的一种异步编程的解决方案,语法行为和传统的函数完全不同。在也语法上可以把Generator函数理解成一个状态机,封装了多个内部状态。
1. Generator函数的特征
a. function关键字和函数名之间有一个星号
b. 函数体内部使用yield表达式,定义不同的内部状态
1 | function* demo(){ |
执行Generator函数会返回一个遍历器对象,Generator函数除了状态机,还是一个遍历器对象生成函数。
2. Generator函数调用
当直接调用Generator函数的时候会返回一个遍历器对象,接下来必须调用遍历器对象的next方法,使得指针移向下一个状态。即每次调用next方法内部指针就从函数的头部或者上一次停下来的地方开始执行,知道遇到下一个yield表达式或者return语句。
Generator函数是分段执行的,yield表达式是暂停执行标记,而next方法是可以恢复执行。
1 | firstDemo.next(); // {value: 'hello', done: false} |
调用分析:
a. 第一次调用,Generator函数开始执行,遇到第一个yield表达式暂停,next方法返回一个对象,value表示当前yield表达式的值,done属性表示遍历是否结束,false为没有结束。
b. 第二次调用,Generator函数从上次暂停的地方开始,执行到下一个yield表达式暂停。next方法返回一个对象,value表示当前yield表达式的值,done属性false为没有结束。
c. 第三次调用,Generator函数从上次暂停的地方开始,执行到return表达式。next方法返回一个对象,value表示当前yield表达式的值,done属性true表示已经结束。
b. 第四次调用,Generator函数此时已经运行完毕。next方法返回一个对象,value为undefined,done属性true为已经结束。
注:如果该函数没有return语句,则返回的对象的value属性值为undefined。
3. yield表达式
由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
yield表达式后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行。
yield表达式与return语句:
a. 相似之处:都能够返回紧跟在语句后面的那个表达式的值
b. 区别: 每次遇到yield函数会暂停执行,下一次再从该位置开始向后执行,而return语句不具备这种记忆功能。一个函数里面只能执行一个或一次return语句,但是可以执行多个或多次yield表达式。
yield表达式的用法:
a. yield表达式只能用在Generator函数里面,用在其他地方都会报错。
b. yield表达式如果用在另一个表达式之中,必须放在圆括号里面。
c. yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号。
4. for…of循环
for…of循环可以自动遍历Generator函数运行时生成的遍历器对象,此时不再需要调用next方法。1
2
3
4
5
6
7
8
9
10
11function* demo(){
yield 1;
yield 2;
yield 3;
yield 4;
return 5;
}
for (let key of demo()) {
console.log(key);
}
// 1 2 3 4
一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的5,不包括在for…of循环之中。
5. return方法
Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数。1
2
3
4
5
6
7
8
9function* demo(){
yield 1;
yield 2;
yield 3;
}
const a = demo();
a.next(); // {value: 1, done: false}
a.return('hello world'); // {vlaue: "hello world", done: true};
a.next(); // {value: undefined, done: true}
如果return方法调用时,不提供参数,则返回值的value属性为undefined。