I am learning this feature from ES6(Function generators) and I am having difficulties to understand the following code :
function* HelloGen2() {
var a = yield 100;
var b = yield a + 100;
console.log(b);
}
var gen2 = HelloGen2();
console.log(gen2.next()); // {value: 100, done: false}
console.log(gen2.next(500)); // {value: 600, done: false}
console.log(gen2.next(1000)); // {value: undefined, done: true}
Questions :
1 : In the first gen2.next()
the line of code var a = yield 100;
is called , is it set some value on the var a
variable ?
2: In each gen2.next() only the line until the semicolon is executed ?
So for instance , in the second call gen2.next(500)
the line console.log(b);
is not executed
3: i do not understand the last line gen2.next(1000)
, how the b variable get the 1000 value ?
When working with coroutines, it's important to understand, that although yield
and next
are different keywords, what they do is essentially the same thing. Imagine two coroutines as being connected by a two-way communication pipe. Both
Y = yield X
and
Y = next(X)
perform the same set of operations:
Initially, the main program is in the active state, and the generator (gen2
in your example) is waiting listening to the pipe. Now, when you call next
, the main program writes a dummy value (null
) to the pipe, thus waking up the generator. The generator executes yield 100
, writes 100
to the pipe and waits. The main wakes up, reads 100
from the pipe, logs it and writes 500
. The generator wakes up, reads 500
into a
, etc. Here's the complete flow:
gen wait
main next() null -> pipe
main wait
gen pipe -> null
gen yield 100 100 -> pipe
gen wait
main pipe -> arg (100)
console.log(arg) 100
main next(500) 500 -> pipe
main wait
gen a= pipe -> a (500)
gen yield a + 100 600 -> pipe
gen wait
main pipe -> arg (600)
console.log(arg) 600
main next(1000) pipe -> 1000
main wait
gen b= pipe -> b
console.log(b) 1000
gen (ended) done -> pipe
main pipe -> arg (done)
console.log(arg)
main (ended)
Essentially, to understand generators, you have to remember that when you assign or somehow else use the result of yield/next
, there's a pause between the right and the left (or "generate" and "use") parts. When you do
var a = 5
this is executed immediately, while
var a = yield 5
involves a pause between =
and yield
. This requires some mental gymnastics, very similar to async
workflows, but with time you'll get used to that.
The relationship between yield x
and generator.next(y)
is as follows:
generator.next(y)
returns {value: x, done: false}
yield x
evaluates to y
Additionally, a generator function doesn't begin execution when initially invoked. You can think of it as a constructor. Only after generator.next()
is called does the actual function code execute until the first yield
statement (or the function terminates).
In your example:
var gen2 = HelloGen2()
creates the generator, but nothing happnes.gen2.next()
executes the function up to yield 100
and then returns {value: 100...}
.gen2.next(500)
resumes function execution, firstly evaluating the yield
statement to 500 (and immediately setting this value into a
), and continue execution up to yield a+100
and then returns {value: 600...}
.gen2.next(1000)
resumes function execution, firstly evaluating the yield
statement to 1000 (and immediately setting this value into b
), and continue execution up to termination and then returns {value: undefined, done: true}
.That last undefined
is the result of the function not returning any value explicitly.
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