Generators in Javascript ES6
Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.
Let’s talk about having a function that prints the letters of the alphabet.
This function will execute all console.log() from top to bottom and we cannot stop it or interact with it in this time period.
Unless the function:
1. Throw some error.
2. Return something.
So how do we for example interact with those internal values of the function while executing? Can we stop and continue executing where we want ?
We can do it with,
Generators
When introducing generators we have to talk about three concepts.
- Function* ()
- Generator Object
- Yield
Function*()
The function*
declaration (function
keyword followed by an asterisk) defines a generator function, which returns a Generator
object.
This type of functions are only differentiated from normal functions by the asterisk (*), which tells us that it is a generator function.
So let´s create our generator function,
Calling a generator function does not execute its body immediately; an generator object for the function is returned instead.
Generator Object
The Generator
object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.
So let´s call our generator object
But why is returning a Object [Generator] {} and not a value?
Because we are not calling the function*, to do it we need to add .next() to our generator.
But now how do we interact with those console.logs within the function?
With the third concept of our generator, yield.
Yield
The yield
keyword is used to pause and resume a generator function (function*
or legacy generator function).
Yield can only be called directly from the generator function that contains it. It can't be called from nested functions or from callbacks.
Let´s add yield to our example,
We see that the first console.log() is executed and then the function stops in yield. Returning the execution outside the function. For example running another console.log() with the string “after”.
We can also return a value with the yield out. But we need to call value when we call the .next() function such that way.
Why an object?
Because .next() method return an Object
with two properties:
value -> Any Value.
value
- any JavaScript value returned by the iterator. Can be omitted whendone
istrue
.
done -> Boolean.
- Has the value
true
if the iterator is past the end of the iterated sequence. In this casevalue
optionally specifies the return value of the iterator. - Has the value
false
if the iterator was able to produce the next value in the sequence. This is equivalent of not specifying thedone
property altogether.