- Lazy evaluation: only execute code when the consumer requests the generator to yield the next value.
- Infinite iterables: dynamically and lazily generate iterable values as we need them, such as a list of all natural numbers (until we stop generating them).
- Identifier generation: one way to create unique identifiers is to share a generator and ask it to yield a new value when a new identifier is needed.
Coding with Generator Functions
We can only create generator functions with the function* declaration; arrow / lambda syntax cannot be used in this case. The example below shows the creation and invocation of a generator function which outputs integers:
Notice that after we've called our generator function, we store its return value into the variable intG, then call next on that variable instead of the function itself. This is a relationship analagous to, but not equal to, the class vs instance relationship. Also notice that the execution of the generator function is paused after each yield keyword. Once .next is called, execution is resumed again until the next yield keyword is reached.
Generator Functions with Parameters
Generator functions accept parameters in the same manner as normal functions. In the example below, our generator function will take two arguments. Notice that the arguments are being passed in when we invoke randomNumberGenerator and not when we invoke next.
Notice the objects which were console logged were not the exact same as what we've yielded. In the next section, we'll discuss why.
Data Type of Yielded Values
- value: the actual value which was given to the yield statement inside of the generator function.
- done: a boolean which will be false if a value is yielded or true if a value is returned.
When the field done is true, the generator function has concluded and should not be invoked again. If it is, no code in the generator itself will be invoked, and the .next call will return a value of undefined. The example below exemplifies this behavior:
The done property enables the consumer to know when the generator has concluded and act appropriately. In some situations, such as our first example, the generator will never conclude. Whether any given generator will conclude or not depends on what it is designed to generate and if it makes sense for it to eventually conclude or continue generating for any arbitrary amount of time.
Passing Arguments into Next Calls
Generator functions allow the consumer to pass in arguments when calling .next. The function receives the input via the yield keyword. The value on the right side of yield is emitted when .next is called, and the value passed into the following .next call will be assigned to the variable on the left side of yield. The generator function below showcases this behavior: