前面的话
Generator函数是ES6提供的一种异步编程的解决方案,语法行为与传统的函数完全不同。
基本概念
从语法上看,首先可以把它理解为一个状态机,封装了多个内部状态;其次执行Generator函数会返回一个遍历器对象,也就是说Generator函数还是一个遍历器对象的生成函数。
从形式上看,Generator函数是一个普通函数,但有两个特征:函数名前面有一个星号;函数体内部使用yield语句定义不同的状态。
function* generator() {
yield 'hello';
yield 'world';
return 'ending'
}
var a = generator();
console.log(a);
上例是一个简单的Generator函数,有两个yield语句,一个return语句,共三种状态。
Generator函数的调用方法与普通函数一样,只是返回的结果不一样,调用。
Generator函数后,函数并不执行,而是返回一个执行内部状态的一个指针对象,即返回一个遍历器对象。
next方法
既然Generator函数返回的是一个指针对象(遍历器对象),那么要想使指针指向下一个状态,就要使用遍历器对象的next()方法。
每次调用next()方法,内部执行就从函数头部或上一次停下的地方开始执行,直到遇到下一个yield语句为止。
function* generator() {
console.log('a');
yield 'hello';
yield 'world';
return 'ending';
}
var a = generator();
console.log( a.next() );
console.log( a.next() );
console.log( a.next() );
console.log( a.next() );
上例中,第一次调用next()方法,Generator函数开始执行,直到遇到第一个yield语句为止。所以结果为: a {value:hello,done: false}
第二次调用,继续执行,知道遇到第二个yield语句,所以结果为:{value: world, done:false}
第三次调用,继续执行,遇到return语句,结果返回:{value: ending, done: true}
第四次调用,此时Generator函数执行完毕,next()返回的对象的value值为undefined,done属性为true。
[总结]:
调用Generator函数返回一个遍历器对象,代表Generator函数的内部指针。以后每次调用遍历器对象的next()方法,就会返回一个有着value和done属性的对象,value表示yield后的表达式的值,done属性是一个布尔值,表示函数是否遍历结束。
[next()方法的运行逻辑]
- 遇到yield语句就暂停执行后面的语句,并将紧跟在yield后的表达式的值作为返回的对象的value属性值
- 下一次调用next()方法时,继续执行,直到遇到下一跳yield语句。
- 如果没有遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式值作为返回对象的value属性值。
- 如果该函数没有return语句,则返回对象value属性值为undefined。
next()方法的参数
yield语句没有返回值或者说返回值为undefined,但如果next()方法带有参数,则这个参数会被当做上一条yield语句的返回值。
function* foo(x) {
var y = 2 * (yield(x + 1));
var z = yield(y/3);
return (x + y + z);
}
var a = foo(5);
// console.log(a.next());
// console.log(a.next());
// console.log(a.next());
console.log(a.next());
console.log(a.next(12));
console.log(a.next(13));
无参数:
有参数:
没有提供参数时,第二次调用next(),导致y的值为2*undefined(即NaN), 第三次调用z为undefined ,返回对象的value属性等于 5+NaN+undefined 为NaN.
提供参数时,第二次调用next(),导致y的值24,第三次调用,使得z的值为13 ,所有返回对象的value值为5+24+13=42
[注意]: 由于next()的参数表示上一条yield语句的返回值,所有第一次使用next方法时,传递的参数是无效的。