javascript - ES6 生成器机制 - 传递给 next() 的第一个值去哪里了?

标签 javascript generator yield

ES6生成器next()传参时,为什么第一个值会被忽略?更具体地说,为什么这个输出是 x = 44 而不是 x = 43:

function* foo() {
    let i = 0;
    var x = 1 + (yield "foo" + (++i));
    console.log(`x = ${x}`);
}

fooer = foo();

console.log(fooer.next(42));
console.log(fooer.next(43));

// output:
// { value: 'foo1', done: false }
// x = 44
// { value: undefined, done: true }

我对这种生成器行为的心智模型是这样的:

  1. 返回 foo1 并在 yield 处暂停(返回 foo1next 调用作为参数 42)
  2. 暂停直到下一次调用next
  3. 在下一个 yield 上继续到带有 var x = 1 + 42 的行,因为这是之前收到的参数
  4. 打印 x = 43
  5. 只需从最后一个 next 返回一个 {done: true},忽略它的参数 (43) 并停止。

现在,显然,这不是正在发生的事情。所以……我在这里弄错了什么?

最佳答案

我最终编写了这种代码以更彻底地调查行为(在重新重新...阅读 MDN docs on generators 之后):

function* bar() {
    pp('in bar');
    console.log(`1. ${yield 100}`);
    console.log(`after 1`);
    console.log(`2. ${yield 200}`);
    console.log(`after 2`);
}
let barer = bar();
pp(`1. next:`, barer.next(1));
pp(`--- done with 1 next(1)\n`);
pp(`2. next:`, barer.next(2));
pp(`--- done with 2 next(2)\n`);
pp(`3. next:`, barer.next(3));
pp(`--- done with 3 next(3)\n`);

输出这个:

in bar
1. next: { value: 100, done: false }
--- done with 1 next(1)

1. 2
after 1
2. next: { value: 200, done: false }
--- done with 2 next(2)

2. 3
after 2
3. next: { value: undefined, done: true }
--- done with 3 next(3)

显然正确的心智模型应该是这样的:

  • 第一次调用 next ,生成器函数体运行到 yield。表达式,yield 的“参数” ( 100 第一次)作为 next 返回的值返回,并且生成器主体暂停之前评估 yield 表达式的值——“之前”部分至关重要

  • 仅在第二次调用 next 时是第一个的值yield表达式计算/替换为 this 调用中给定的参数值(而不是像我预期的那样用 previous 中给出的参数值),并且执行一直运行到第二 yield , 和 next返回第二个 yield 的参数值 -- 这是我的错误: 我假设了 第一个 yield 的值表达式第一次调用next 的参数,但它实际上是 第二次调用 next 的参数,或者换句话说,它是 调用 next 的参数在其执行期间实际计算值

这对于发明者来说可能更有意义,因为对 next 的调用次数是yield的多一倍语句(还有最后一个返回 { value: undefined, done: true } 信号终止),所以如果第一个调用的参数不会被忽略,那么最后一个调用的参数就必须被忽略。此外,在评估 next 的主体时,替换将从其 previous 调用的参数开始。恕我直言,这会更直观,但我认为这也是关于遵循其他语言中生成器的约定,而一致性最终是最好的...


题外话但很有启发性:刚刚尝试在 Python 中做同样的探索,它显然实现了类似于 Javascript 的生成器,我立即得到了 TypeError: can't send non-None value to a just-started generator当试图将参数传递给第一次调用 next() 时(清楚地表明我的心智模型是错误的!),迭代器 API 也以抛出 StopIteration 结束。异常(exception),所以没有“额外”next()只需要检查 done 是否是真的(我想象使用这个额外的调用来产生利用最后一个 next 参数的副作用只会导致非常难以理解和调试代码...)。比在 JS 中更容易“理解它”...

关于javascript - ES6 生成器机制 - 传递给 next() 的第一个值去哪里了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44246673/

相关文章:

c# - 网页的电子邮件内容

python - 每次只返回一个数字的随机数生成器

javascript - 干净的箭头函数 - 对数组中的多个元素调用生成器

javascript - 函数生成器javascript

python - 当你调用一个包含 yield 的函数时会发生什么?

python - python并发下载和处理大文件

javascript - Node Js : Unable to find error in below file filter code

javascript - js 行导致它上面的代码不执行

javascript - AngularJS ng-repeat 了解如何查找复选框值

python - 使用 Python 将一个字符替换为多个字符