Generator and Iterator ⚙️
Questions 🤔
- What are generator and iterator
- How generator function is different from regular function
- What denotes a generator function
- What are function and function
- Is the below syntax is right?
- What is the role of
yield
- How
yield
is different thanyield*
- What does generator object will contain
- What is generator composition and how can we achieve it?
- How to break a generator
So far we have seen the Javascript function can return an only single value, multiple values in a single object or nothing but have you ever thought that how can one function return multiple values? Is it really possible?
Yes, it is possible with the help of Generator Functions
A generator function can return multiple values one after other using its generator object
Generator functions
To create a generator function we need to suffix a function
keyword with *
something like this function*
which will make a function as a generator
Generator functions behave differently from regular ones. When such a function is called, it doesn’t run its code. Instead, it returns a special object, called generator object
, to manage the execution.
The main method in the generator object
is next()
. When called, it runs the execution until the nearest yield <value>
statement (value can be omitted, then it’s undefined
). Then the function execution pauses, and the yielded value is returned to the outer code.
The result of next()
is always an object with two properties
value
: the yielded valuedone
:true
if the function code has finished, otherwisefalse
Generator Object Methods and States
next()
Returns the next value in a generatorreturn()
Returns a value in a generator and finishes the generatorthrow()
Throws an error and finishes the generatorsuspended
Generator has halted execution but has not terminatedclosed
Generator has terminated by either encountering an error, returning, or iterating through all values
In the above code, the generator myGenerator
returns 3 different results highlighted one, and the in the third log value of done
is true
which means generator notifies that there is no other value left to return. This is the real beauty of the generator
Remember
A generator will remember the last returned value. When we call next time it will not return the previously returned value instead it will return next value if any value present
We can't make anonymous function and arrow function as a generator function if we do so Javascript will throw an error Function statements require a function name / Unexpected token '*'
yield
Operators
Generators introduce a new keyword to JavaScript: yield
. yield
can pause a generator function and return the value that follows yield
, providing a lightweight way to iterate through values.
Now, when we call next()
on the generator function, it will pause every time it encounters yield
. done
will be set to false
after each yield, indicating that the generator has not finished. Once it encounters a return, or there are no more yields encountered in the function, done
will flip to true
, and the generator will be finished.
Iterating Over a Generator
Generators are iterators which means we can loop over the generator methods
If you see the above code result it will return only first two value but it hasn't returned third value that is Hi Beautiful People
It’s because for..of
iteration ignores the last value, when done: true
. So, if we want all results to be shown by for..of
, we must return them with yield
As generators are iterable, we can call all related functionality, e.g. the spread syntax ...
In the code above, ...myGenerator() turns the iterable generator object into an array of items. to know more how that works read about spread and rest syntax
Using generators for iterables
Let's see with one sample code of generator for iterables
We can use a generator function for iteration by providing it as Symbol.iterator.
We still do have a scope to reduce no of lines
That works, because range[Symbol.iterator]()
now returns a generator, and generator methods are exactly what for..of
expects. it has a .next()
method that returns values in the form {value: ..., done: true/false}
Generator composition
Generator composition is a special feature of generators that allows to transparently embed generators in each other
For instance, we have a function that generates a sequence of numbers:
Now we’d like to reuse it to generate a more complex sequence
- First, digits 0..9 (with character codes 48…57),
- followed by uppercase alphabet letters A..Z (character codes 65…90)
- followed by lowercase alphabet letters a..z (character codes 97…122
The yield*
directive delegates the execution to another generator. This term means that yield* gen
iterates over the generator gen
and transparently forwards its yields outside. As if the values were yielded by the outer generator.
The result is the same as if we inlined the code from nested generators
Note: The above code snippet is taken from Javascript info
Closing a Generator
As we've seen, a generator can have its done
property set to true
and it's status set to closed by iterating through all its values. There are two additional ways to immediately cancel a generator: with the return()
method, and with the throw()
method.
With return()
, the generator can be terminated at any point, just as if a return statement had been in the function body. You can pass an argument into return()
, or leave it blank for an undefined value.
The first next()
will give us 'Hello Hackers', with done
set to false. If we invoke a return()
method on the Generator object right after that, we'll now get the passed value and done set to true
. Any additional call to next()
will give the default completed generator response with an undefined
value.
Reference