第一个 next() 调用的参数去哪里了?

Where argument of first next() call goes?

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

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,您可以在其中看到该结果。

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

'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') 上,您 运行 直到第一个 yield 通过生成器中的 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 值,如果您在生成器上省略 return,则将是 undefined

next方法定义如下:

25.3.1.2 Generator.prototype.next ( value )

The next method performs the following steps:

  1. Let g be the this value.
  2. Return GeneratorResume(g, value).

GeneratorResume 抽象操作在第 10 步使用

25.3.3.3 GeneratorResume ( generator, value )

The abstract operation GeneratorResume with arguments generator and value performs the following steps:

  1. Let genContext be the value of generator’s [[GeneratorContext]] internal slot.

  1. Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation that suspended it. Let result be the value returned by the resumed computation.

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

其行为在 14.4.14 Runtime Semantics: Evaluation:

中有解释

YieldExpression : yield

  1. Return GeneratorYield(CreateIterResultObject(undefined, false)).

(类似于 YieldExpressionyield AssignmentExpression

GeneratorYield抽象操作挂起生成器如下:

  1. Set the code evaluation state of genContext such that when evaluation is resumed with a Completion resumptionValue the following steps will be performed:

    1. Return resumptionValue.
    2. NOTE: This returns to the evaluation of the YieldExpression production that originally called this abstract operation.

因此作为第二个 next 的参数传递的值用作第一个 yield 表达式的返回值。作为第 3 个 next 的参数传递的值用作第 2 个 yield 表达式的返回值。等等。

不过,也有可能发电机还没有启动(即"suspendedStart"状态)。

这是通过GeneratorStart抽象操作完成的:

  1. Set the code evaluation state of genContext such that when evaluation is resumed for that execution context the following steps will be performed:

但是那些"following steps"不使用恢复值。

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