Reputation: 28562
I have a piece of code:
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"))
When you run it you will get the following output:
{ value: [], done: false }
{ value: [ 'B' ], done: false }
{ value: [ 'B', 'C' ], done: false }
{ value: [ 'B', 'C', 'D' ], done: false }
Why the first line of the result doesn't include A
in the array?
There is one explanation from this page at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*#Passing_arguments_into_Generators. The comment says
the first call of next() executes from the start of the function until the first yield statement
But from my testing it seems not correct. My testing code is:
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());
The result is:
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 }
As you can see, the first next()
not only executed the statements before the first yield
, but also the first yield
statement. So that theory can't explain my question. Can anyone help to point me the right direction? Thanks in advance.
Upvotes: 3
Views: 118
Reputation: 1292
Consider the first generator you wrote rewritten this way.
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"))
Isn't it clearer to see why "A" never gets added to the array? The first execution of the generator stops at the first yield statement well before the array ever gets modified. By the time execution returns to the generator, the passed in value is "B". The same dynamic is occurring in your code here array.push(yield array);
Inner expressions are evaluated first, thus the yield
halts execution before the push
is accessed.
I believe that if you want to the generator to respect the first value you pass in, you need to call .next() once without any parameters. Every example I've seen does this.
Also reading the "Send" section of this article illustrates your situation.
Note that this model works well for a question and answer type interaction since we cannot have an answer before a question is asked, and all subsequent next
calls will pass in the answer to the previous question and retrieve the next one.
var q1 = gen.next();
console.log(q1);
var a = userInput();
var q2 = gen.next(a);
console.log(q2);
var a2 = userInput();
...
Upvotes: 1
Reputation: 14777
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
Notice that the var gen = foo()
merely creates an instance of a generator. It's the first invocation of .next()
that starts the execution of the generator. Generators execute until they reach a yield
statement and return the value of that yield
statement. At this point the generator is paused until another invocation of .next()
is performed.
So, everything is working as intended in your examples. In the first example, the first yield
statement is returning the empty array. On the next .next()
the array is populated with the value passed in, and then that array is yielded. In code:
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
}
This matches the documentation:
If an optional value is passed to the generator's next() method, that value becomes the value returned by the generator's current yield operation.
Upvotes: 0