【问题标题】:Where argument of first next() call goes? [duplicate]第一个 next() 调用的参数在哪里? [复制]
【发布时间】:2015-12-03 11:38:15
【问题描述】:

我有一个简单的生成器函数

function *generate(arg) {
  console.log(arg)
  for(let i = 0; i < 3;i++) {
    console.log(yield i);
  }
}

然后我启动生成器并尝试在控制台中打印值:

var gen = generate('arg'); //doesn't print
gen.next('a'); // prints 'arg'
gen.next('b'); // prints 'b'
gen.next('c'); // prints 'c'
// ... nothing surprising later

第一个next() 调用的参数a 去哪儿了?有没有办法在生成器函数中使用它?

这是Babel REPL,您可以在其中看到该结果。

【问题讨论】:

  • 第一个next 开始执行生成器。你不能使用你传递给它的值;它被扔掉了。除了undefined 之外,您也不允许传递任何东西来明确这一点,但这可能已经改变,因为您没有收到 TypeError: wiki.ecmascript.org/doku.php?id=harmony:generators (请参阅内部方法下的 If state = “newborn”:send)。
  • 好吧,如果在草稿版本中它被设计为抛出错误,我可以确定,这个参数不应该被生成器访问。感谢您的评论!
  • @minitech:我相信他们正在讨论一种如何访问 ES7 中第一次调用的参数的方法。

标签: javascript node.js generator ecmascript-6


【解决方案1】:

next方法定义如下:

25.3.1.2 Generator.prototype.next ( value )

next 方法执行以下步骤:

  1. 让 g 为 this 值。
  2. 返回GeneratorResume(g, 值)。

GeneratorResume 抽象操作在第 10 步使用 value:

25.3.3.3 GeneratorResume ( generator, value )

带有参数的抽象操作 GeneratorResume 和 value 执行以下步骤:

  1. 让 genContext 为 generator 的 [[GeneratorContext]] internal slot 的值。

  1. 使用 NormalCompletion(value) 作为操作的结果,恢复 genContext 的 suspended 评估 suspended它。令 result 为被恢复的返回值 计算。

第一种可能是使用yield(即"suspendedYield"状态)暂停了评估。

它的行为在14.4.14 Runtime Semantics: Evaluation中解释:

YieldExpression : yield

  1. 返回GeneratorYield(CreateIterResultObject(未定义, 错误))。

(类似于YieldExpression:yieldAssignmentExpression)

GeneratorYield 抽象操作暂停生成器,如下所示:

  1. 设置 genContext 的代码评估状态,以便在使用 Completion resumptionValue 恢复评估时 将执行以下步骤:

    1. 返回resumptionValue。
    2. 注意:这将返回到最初调用此抽象操作的 YieldExpression 产生式的评估。

所以作为第二个next 的参数传递的值被用作第一个yield 表达式的返回值。并且作为第三个next 的参数传递的值用作第二个yield 表达式的返回值。以此类推。

但是,也有可能生成器尚未启动(即"suspendedStart" 状态)。

这是由GeneratorStart抽象操作完成的:

  1. 设置 genContext 的代码评估状态,以便在为 execution context 恢复评估时,以下内容 将执行的步骤:

但那些“后续步骤”不使用恢复值。

因此,作为第一个 next 的参数传递的值被丢弃。

【讨论】:

  • 但是,有人提议添加一个新的元属性以使其可用。
  • @Bergi 有趣。你能链接那个提案吗?
  • 我猜是this one。 es-discuss 上也有一个附带的帖子,但我现在找不到它
【解决方案2】:

不,您不能使用第一个值。如果您将代码更改为:

'use strict';
function *generate(arg) {
  console.log(arg)
  for(let i = 0; i < 3;i++) {
    console.log(yield i);
  }
  return 'done';
}

var gen = generate('arg');
console.log(gen.next('a'));
console.log(gen.next('b'));
console.log(gen.next('c'));
console.log(gen.next('d'));

当您实例化生成器时,它还没有开始执行并且没有任何记录。在第一个gen.next('a') 上,您运行到第一个产量,它通过生成器中的console.log(arg),然后执行yield 0。然后在调用者中得到console.log,你得到{value: 0, done:false},等等,直到你完成迭代。整体输出如下:

arg
{ value: 0, done: false }
b
{ value: 1, done: false }
c
{ value: 2, done: false }
d
{ value: 'done', done: true }

最后的done 是返回值,如果你在生成器上省略return,它将是undefined。

【讨论】:

  • 其实这不是关于next之后发生的事情的问题。问题是关于第一个论点以及它在哪里使用。 @minitech♦ 给出了正确答案——无处,它被设计为消失
猜你喜欢
  • 2017-10-30
  • 2014-02-07
  • 2021-11-15
  • 2013-10-06
  • 2010-11-19
  • 2014-01-25
  • 1970-01-01
  • 2018-01-14
相关资源
最近更新 更多