The documentation says that "You can also provide a parameter to the next method to send a value to the generator." Where does it sends it to?
For example, take these 3 generators:
function* one() {
while(true) {
var value = yield null;
}
}
var g1 = one(); g1.next();
g1.next(1000); //yields null
function* two() {
var i = 0;
while (true) {
i += yield i;
}
}
var g2 = two(); g2.next();
g2.next(1000) // yields 1000
function* three(){
var index = 0;
while (true)
yield index++;
}
g3 = three();
g3.next();
g3.next(1000); // yields 1
In generators 3 and 1, the argument passed has no effect on next
. Why is that? How does generator 2 calculates its return value? Why it is affected by the given argument?
next() method is an inbuilt method in JavaScript which is used to return an object with two properties done and value.
Generator functions provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function whose execution is not continuous. Generator functions are written using the function* syntax. When called, generator functions do not initially execute their code.
In JavaScript, generators provide a new way to work with functions and iterators. Using a generator, you can stop the execution of a function from anywhere inside the function. and continue executing code from a halted position.
The function* declaration ( function keyword followed by an asterisk) defines a generator function, which returns a Generator object.
The key to understanding this is knowing how the next function retrieves the argument passed to next()
, which is as the return value of the yield operator:
[rv] = yield [expression];
Independently of the value of [expression], yield will assign to rv
the value passed to next()
.
But, here comes the tricky part: yield will only assign the value passed to next() when resuming execution from a previous iteration. As a consequence, on the first iteration, yield
does not assign anything to rv.
For example, if I have this generator:
function* gen() {
// On the first iteration, yield does not return anything.
//because it returns something ONLY when execution is resumed
returnedFromYield = yield 'foo';
yield returnedFromYield;
}
returnedFromYield
is undefined on the first iteration. When execution is resumed on the second iteration, yield assigns the passed value to the returnedFromYield
variable, which is then returned:
g.next(1); // 'foo'
g.next(2); // 2
Let's review another example:
function* gen() {
yield yield yield 5;
}
On the first iteration, (g.next()
), yield will return 5, on the second iteration, (g.next(10)
) yield is going to pass 10 to the second yield. That is, yield yield yield 5;
on the second iteration is equivalent to yield yield 10;
, and, on the third iteration, it's equivalent to yield valuePassedToNext
.
Here's an annotated example showing the logical flow and scope for the values passed to a generator's next method. The affected area of the next
method call is highlighted in the corresponding color.
a: There is no yield, so argument 'one' is ignored. The generator pauses on line 5, returning the value 1.
b: Execution resumes and 'two' replaces yield on line 5, and is assigned to the yieldValue
variable. Line 6 is executed. The generator pauses on line 8, returning the value 2.
c: Execution resumes and 'three' replaces yield on line 8, and is assigned to the yieldValue
variable. Line 9 is executed. The generator pauses on line 11, returning the value 3.
d: Execution resumes and 'four' replaces yield on line 11, and is assigned to the yieldValue
variable. Line 12 is executed. Line 14 is executed. Finally the generator is now done, returning the value undefined
.
See the logs on line 28-36
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