基础知识
调用生成器函数会返回一个迭代器。
在迭代器上调用.next()
会返回一个对象,格式如下:
{
value
done
}
在生成器提供的迭代器上调用
.next()
方法会从
生成器中当前暂停的点到下一个yield
运行代码,将生成器在这个下一个
yield
处暂停,并将任何
yield
值作为对象形式从迭代器的
.next()
方法中返回的值推出。
您传递给此迭代器的任何内容都将从生成器中当前暂停的yield
返回。
由于在第一次调用.next()
时生成器没有在yield
上暂停,因此传递给第一个.next()
的任何内容都将被忽略。
如果没有剩余的yield
语句,则函数返回的任何内容都将是最后的迭代器值。
此时,done
标志将设置为true
,任何进一步调用.next()
都将返回相同的值。
运行示例
因此,在您的代码方面,以下是正在发生的情况。我将注释每个执行步骤之后发生的每一行。
步骤1
f = foo()
此时,迭代器被创建并存储在变量f
中,但是生成器中的任何代码都没有实际运行。因此我们有:
function* () {
console.log('generator 1');
console.log('yield 1', yield 'A');
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
步骤2
f.next('a');
这将运行生成器中第一个yield
之前的代码,并将产生的'A'
从.next()
调用中推出。传递到.next()
的'a'
只是被忽略了,因为这是第一次调用(如上所述)。
注释掉运行的行,我们得到:
function* () {
console.log('yield 1', PAUSE_POINT);
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
第三步
f.next('b'); // return { value: 'B', done: false }
这将从第一个yield
(第一个PAUSE_POINT
)返回'b'
,并运行代码到下一个yield
,从迭代器中推出'B'
。
删除运行的代码后,剩下:
function* () {
console.log('yield 2', PAUSE_POINT);
console.log('generator 3');
};
第四步
f.next('c'); // { value: undefined, done: true }
当生成器暂停时,它会传递出'c'
,由于没有更多的yields
,它将运行到生成器的结尾并推出生成器返回的任何内容,而在您的情况下,这只是隐式的return undefined
。由于我们到达了生成器函数的结尾,done
标志设置为true
。
function* () {
};
第五步及以后
f.next('d'); // { value: undefined, done: true }
当生成器完成(即done
为true
)后,对.next()
的任何调用都只会返回最后一个值。将'd'
传递到此方法中已经没有意义了。
附加示例
var foo = function* () {
console.log('first call to next runs to yield #1');
var a = yield 'A';
console.log('second call to next runs to yield #2');
var b = yield 'B';
console.log('third call to next runs to the end of the generator ');
};
var f = foo();
console.log(f.next('this gets ignored'));
console.log(f.next('a'));
console.log(f.next('b'));
console.log(f.next('this also gets ignored since we are done'));