the*_*lqd 3 javascript generator ecmascript-6
我从一篇文章中读到了这行代码,它们展示了函数生成器的工作流程。
var foo, f;
foo = 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');
};
f = foo();
console.log('tick 1');
console.log(f.next('a'));
console.log('tick 2');
console.log(f.next('b'));
console.log('tick 3');
console.log(f.next('c'));
console.log('tick 4');
console.log(f.next('d'));
Run Code Online (Sandbox Code Playgroud)
这是终端中的日志:
tick 1
generator 1
{ value: 'A', done: false }
tick 2
yield 1 b
generator 2
{ value: 'B', done: false }
tick 3
yield 2 c
generator 3
{ value: undefined, done: true }
tick 4
{ value: undefined, done: true }
Run Code Online (Sandbox Code Playgroud)
但我找不到轻松理解这个流程的方法,这有点奇怪。如果有人对这个问题有简单的方法,请帮忙解释一下。
调用生成器函数会返回一个迭代器。
调用.next()迭代器会返回一个以下形式的对象:
{
value // current value of the iterator,
done // boolean indicating if iteration is finished
}
Run Code Online (Sandbox Code Playgroud)
调用.next()生成器提供的迭代器,从生成器中当前暂停点运行代码到下一个yield,在下一个暂停生成器yield,并推出迭代器方法yield返回的值,在.next()对象形式如上所示。
您传递给.next()此迭代器的任何内容都将从yield生成器中当前暂停的状态返回。
由于生成器不会yield在第一次调用a 时暂停.next(),因此传递到第一个.next()is 的任何内容都会被忽略。
如果没有yield剩余语句,则函数返回的任何内容都将是最后一个迭代器值。
此时,done标志将被设置为true,并且任何进一步的调用都.next()将返回相同的值。
因此,就您的代码而言,这就是正在发生的事情。我将注释掉执行步骤后发生的每一行。
步骤1
f = foo();
Run Code Online (Sandbox Code Playgroud)
此时,迭代器已创建并存储在其中,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');
};
Run Code Online (Sandbox Code Playgroud)
第2步
f.next('a'); // returns { value: 'A', done: false }
Run Code Online (Sandbox Code Playgroud)
这会运行生成器中的代码直到第一个代码yield,并将生成的代码推出'A'调用.next()。'a'传入的被.next()忽略,因为它是第一次调用(如上所述)。
注释掉运行的行留给我们:
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');
};
Run Code Online (Sandbox Code Playgroud)
步骤3
f.next('b'); // return { value: 'B', done: false }
Run Code Online (Sandbox Code Playgroud)
这'b'从第一个yield(第一个PAUSE_POINT)返回并运行代码到下一个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');
};
Run Code Online (Sandbox Code Playgroud)
步骤4
f.next('c'); // { value: undefined, done: true }
Run Code Online (Sandbox Code Playgroud)
它'c'从暂停中传递出来yield,并且由于没有剩余的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;
};
Run Code Online (Sandbox Code Playgroud)
步骤 5 及后续步骤
f.next('d'); // { value: undefined, done: true }
Run Code Online (Sandbox Code Playgroud)
.next()生成器完成后(即doneis )的任何调用true都只会返回最后一个值。传递'd'到这个方法已经没有任何意义了。
{
value // current value of the iterator,
done // boolean indicating if iteration is finished
}
Run Code Online (Sandbox Code Playgroud)