3

我有一段代码:

function * input(){
    let array = [];
    while(true) {
        array.push(yield array);
    }
}

var gen = input();
console.log(gen.next("A"))
console.log(gen.next("B"))
console.log(gen.next("C"))
console.log(gen.next("D"))

当你运行它时,你会得到以下输出:

{ value: [], done: false }
{ value: [ 'B' ], done: false }
{ value: [ 'B', 'C' ], done: false }
{ value: [ 'B', 'C', 'D' ], done: false }

为什么结果的第一行不包含A在数组中?此页面在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*#Passing_arguments_into_Generators有一个解释。评论说

next() 的第一次调用从函数开始执行到第一个 yield 语句

但从我的测试来看,它似乎不正确。我的测试代码是:

function* logGenerator() {
    console.log("before yield in function");
    yield 1;
    console.log("filler 1");
    yield 2;
    console.log("filler 2");
    yield 3;
    console.log("filler 3");
}

var gen = logGenerator();

console.log(gen.next());
console.log("-----------------");
console.log(gen.next());
console.log("-----------------");
console.log(gen.next());
console.log("-----------------");
console.log(gen.next());

结果是:

before yield in function
{ value: 1, done: false }
-----------------
filler 1
{ value: 2, done: false }
-----------------
filler 2
{ value: 3, done: false }
-----------------
filler 3
{ value: undefined, done: true }

如您所见, firstnext()不仅执行了 first 之前的语句yield,还执行了第一yield条语句。所以这个理论无法解释我的问题。谁能帮我指出正确的方向?提前致谢。

4

2 回答 2

1

考虑以这种方式重写的第一个生成器。

function * input(){
    let array = [];
    while(true) {
        var thingToAdd = yield array;
        console.log(thingToAdd);
        array.push(thingToAdd);
    }
}

var gen = input();
console.log(gen.next("A"))
console.log(gen.next("B"))
console.log(gen.next("C"))
console.log(gen.next("D"))

看看为什么“A”永远不会被添加到数组中不是更清楚吗?生成器的第一次执行在数组被修改之前的第一个 yield 语句处停止。当执行返回到生成器时,传入的值为“B”。同样的动态发生在您的代码array.push(yield array); 中,首先评估内部表达式,因此在访问yield之前暂停执行push

我相信,如果您希望生成器尊重您传入的第一个值,则需要在不带任何参数的情况下调用 .next() 一次。我见过的每个例子都是这样做的。

另请阅读本文的“发送”部分说明您的情况。

请注意,此模型适用于问答类型的交互,因为在提出问题之前我们无法获得答案,并且所有后续next调用都将传递上一个问题的答案并检索下一个问题。

var q1 = gen.next();
console.log(q1);
var a = userInput();
var q2 = gen.next(a);
console.log(q2);
var a2 = userInput();
...
于 2017-01-17T19:09:20.087 回答
0
function * foo () {
  var i = 0
  yield i

  i += 1
  yield i

  i += 1
  i += 2
  yield i
}

var gen = foo()
console.log(gen.next()) // 0
console.log(gen.next()) // 1
console.log(gen.next()) // 4

请注意,这var gen = foo()只是创建了一个生成器的实例。.next()这是开始执行生成器的第一次调用。生成器一直执行,直到它们到达一条yield语句并返回该yield语句的值。此时生成器暂停,直到.next()执行另一个调用。

因此,一切都按您的示例中的预期工作。在第一个示例中,第一yield条语句返回空数组。在下一个.next()数组中填充传入的值,然后生成该数组。在代码中:

function * foo (param) {
  var array = []
  // do nothing with param
  yield array

  array.push(param) // 'B'
  yield array

  array.push(param) // 'C'
  yield array

  array.push(param) // 'D'
  yield array
}

这与文档匹配:

如果将可选值传递给生成器的 next() 方法,则该值将成为生成器当前 yield 操作返回的值。

于 2017-01-17T19:16:13.313 回答