基础知识
调用生成器函数会返回一个iterator。
在迭代器上调用 .next() 会返回以下形式的对象:
{
value // current value of the iterator,
done // boolean indicating if iteration is finished
}
在生成器提供的迭代器上调用.next(),将代码从生成器中的当前暂停点运行到下一个yield,在下一个yield 上暂停生成器,然后将yield 的值作为迭代器的.next() 方法返回的值,以上面显示的对象形式推出。
您传递给此迭代器的.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'); // returns { value: 'A', done: false }
这会在生成器中运行代码直到第一个 yield 并将产生的 'A' 从 .next() 调用中推出。传递给 .next() 的 'a' 将被忽略,因为它是第一次调用(如上所述)。
注释掉运行的行给我们留下:
function* () {
// console.log('generator 1');
console.log('yield 1', PAUSE_POINT); // we're paused on the `yield`. Essentially half of this line is done
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
第 3 步
f.next('b'); // return { value: 'B', done: false }
这会从第一个yield(第一个PAUSE_POINT)返回'b',并将代码运行到下一个yield,将'B'从迭代器中推出。
删除运行留下的行:
function* () {
// console.log('generator 1');
// console.log('yield 1', 'b'); // this PAUSE_POINT returns 'b'
// console.log('generator 2');
console.log('yield 2', PAUSE_POINT); // no we're paused here
console.log('generator 3');
};
第 4 步
f.next('c'); // { value: undefined, done: true }
从暂停的yield 中传递'c' 并且由于没有更多yields 离开,运行到生成器的末尾并推出生成器返回的任何内容,在您的情况下这只是一个隐含的return undefined。由于我们到达了生成器函数的末尾,done 标志设置为true。
function* () {
// console.log('generator 1');
// console.log('yield 1', 'b'); // this PAUSE_POINT returns 'b'
// console.log('generator 2');
// console.log('yield 2', 'c'); // this PAUSE_POINT returns 'c'
// console.log('generator 3');
// here we have an implicit return undefined;
};
第 5 步及后续步骤
f.next('d'); // { value: undefined, done: true }
生成器完成后对.next() 的任何调用(即done 是true)只会返回最后一个值。将'd' 传递到此方法中不再有用。
附加示例
var foo = function* () {
console.log('first call to next runs to yield #1');
var a = yield 'A'; // this yield pushes 'A' and returns 'a'
console.log('second call to next runs to yield #2');
var b = yield 'B'; // this yield pushes 'B' and returns 'b'
console.log('third call to next runs to the end of the generator ');
// there's no return statement here so we are returning undefined
};
var f = foo();
console.log(f.next('this gets ignored')); // { value: 'A', done: false }
console.log(f.next('a')); // { value: 'B', done: false }
console.log(f.next('b')); // { value: undefined, done: true }
// any further call just returns whatever the last returned value was
console.log(f.next('this also gets ignored since we are done')); // { value: undefined, done: true }