Reputation: 561
MDN suggested that "When the iterator's next() method is called, the generator function's body is executed until the first yield expression" and I do understand this example:
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
var gen = logGenerator();
gen.next(); // 0
gen.next('pretzel'); // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise
However, I am confused when I come across another example:
const foo = function*() {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
If the first next()
only execute code BEFORE the first yield, the value should be undefined. How does it pick up the value WITHIN the first yield? I am a bit confused here. Thanks for helping out.
Upvotes: 6
Views: 2024
Reputation: 782775
You can see what's going on better by logging what the generator yields each time, as well as adding values to the yield
expressions so you can see what the generator is actually yielding (the MDN example didn't bother with this because it never uses the yielded values, it was just demonstrating the way the next()
argument works).
Typically, you wouldn't use a single generator to yield values and also receive values through the next()
argument, just one or the other. If it yields values, you would use yield <expression>
as a statement by itself (similar to return
), not generally inside an expression. If it receives values you use yield
without a parameter inside an expression. But as you can see with my modified example, the underlying mechanism allows both at the same time. You just need to keep track of the confusing order of execution.
function* logGenerator() {
console.log(0);
console.log(1, yield 10);
console.log(2, yield 20);
console.log(3, yield 30);
}
var gen = logGenerator();
console.log("call 1 yielded", gen.next().value); // 0
console.log("call 2 yielded", gen.next('pretzel').value); // 1 pretzel
console.log("call 3 yielded", gen.next('california').value); // 2 california
console.log("call 4 yielded", gen.next('mayonnaise').value); // 3 mayonnaise
The first time you call the generator is executes console.log(0);
and then starts executing console.log(1, yield 10)
. But when it gets to the yield
expression, next()
returns that value, before actually calling console.log()
.
The next time you call the generator, it resumes where it left off, which is constructing the arguments to console.log()
. The yield 10
expression is replaced with the argument to next()
, so it executes console.log(1, 'pretzel')
.
Then it starts executing console.log(2, yield 20)
, and the same thing happens -- it yields 20
before calling console.log()
.
What MDN was trying to show is that the argument to next()
is only meaningful starting on the second call, because it replaces the value of yield
in the interrupted expression when the generator resumes. Using an argument on the first call has no effect, because there's no interrupted expression to replace.
Upvotes: 5