了解Javascript的生成器

时间:2017-01-17 18:12:37

标签: javascript generator yield yield-keyword

我有一段代码:

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 }

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

  

next()的第一次调用从函数的开头执行   直到第一个收益率陈述

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

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 }

如您所见,第一个next()不仅执行了第一个yield之前的语句,还执行了第一个yield语句。所以这个理论无法解释我的问题。任何人都可以帮我指出正确的方向吗?提前谢谢。

2 个答案:

答案 0 :(得分: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()一次。我见过的每个例子都是这样做的。

另请阅读this article的“发送”部分说明了您的情况。

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

var q1 = gen.next();
console.log(q1);
var a = userInput();
var q2 = gen.next(a);
console.log(q2);
var a2 = userInput();
...

答案 1 :(得分: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
}

匹配the documentation

  

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