I stumbled on generator functions on MDN and what puzzles me is the following example:
function* logGenerator() {
console.log(yield);
console.log(yield);
console.log(yield);
}
var gen = logGenerator();
// the first call of next executes from the start of the function
// until the first yield statement
gen.next();
gen.next('pretzel'); // pretzel
gen.next('california'); // california
gen.next('mayonnaise'); // mayonnaise
What I don't understand is why the yield
statement which is the argument of console.log
returns the parameter passed to the .next()
method of the generator. Is this happening because an empty yield
must return the value of the first parameter of the .next()
method?
I have also tried some more examples, which seem to confirm the above statement like:
gen.next(1,2,3); // the printed value is 1, the 2 and 3 are ignored
// and the actual yielded value is undefined
Also is there a way to access the further parameters of the .next()
method inside the body of the generator function?
Another thing I noticed is, while the yield statement is returning these values to the console.log
they are actually not yielded as the output of the generator. I must say I find it very confusing.
In JavaScript, yield is used to pause the execution of a function. When the function is invoked again, the execution continues from the last yield statement. A generator returns a generator object, which is an iterator. This object generates one value at a time and then pauses execution.
Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).
When called, generator functions do not initially execute their code. Instead, they return a special type of iterator, called a Generator. When a value is consumed by calling the generator's next method, the Generator function executes until it encounters the yield keyword.
Great question. I think reading the MDN on the .next()
method is most helpful. You can define the value you want to pass within the generator function itself (i.e. yield 1
) or pass the value via next()
by saying something like gen.next(1)
The next()
method itself returns an Object, with the properties value
and a boolean done
which signifies whether the generator function is complete (i.e. exhausted of available outputs and will now output only undefined
for a value).
That said, there are two ways to access / pass it that value
.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next
The confusion comes from the fact that yield
and next
have different syntaxes, while they actually do the same thing. Generator and its caller are symmetric (that's why they are called "co"-routines and not "sub"-routines). Both functions can be thought as connected by a communication channel, and can either do their job or sleep waiting for an incoming message in the channel. The only difference is that the generator is initially asleep (that is, there's an implicit "listen" command at the top of it), while the caller is initially awake.
Both yield
and next
do the same thing three things:
Illustration:
_ = console.log.bind(console)
function *gen() {
_('gen: good morning')
_('gen: sending hi')
_('gen: zzz')
p = yield 'hi'
_('gen: awake! got', p)
_('gen: now sending fine')
_('gen: zzz')
p = yield 'fine'
_('gen: awake! got', p) // ***
}
function main() {
var g = gen()
_('main: sending knock knock')
_('main: zzz')
r = g.next('knock knock')
_('main: awake! got', r)
_('main: sending how r u')
_('main: zzz')
r = g.next('how r u')
_('main: awake! got', r)
}
main()
Note that since write comes before read, the very first message sent to the generator is lost. It's only used to wake up the generator. Also note how we've left the generator in the sleeping state, so the ***
line is not reached.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With