What are generators and how can I use them?
How do you write loops in Javascript - Simple for/while? Recursion? In other less exciting ways?
How do you throttle and control function execution? Debounce function? Build your own?
What if you could produce the right mix of reusable functions, looping and throttling in one go? Enter generators.
What are Generators?
Generators are functions that lets you can control iteration. You can use generators to suspend execution of a function while saving the context for continuing the execution at a later time.
MDN defines generators as functions which can be exited and later re-entered.
Let’s understand more with an example -
|
|
In the code block -
- We have defined the generator function using
function*
prefix - We used a keyword
yield
indicates to Javascript that the function needs to go into sleep and return the said value - Initiated the function
- Called the generator function multiple times - with each time stopping at the next
yield
to return a value
Simple enough?
What’s mondo interesting about this function is the ability to store a state without impacting the program flow. And each time we invoke the function with a next()
, the state is back with a bang and execution continues as if nothing happened.
Defining generators
We can use any of the following ways to define generator functions-
|
|
I just stick to what Prettier tells me to do.
Also, we cannot use arrow functions for generators yet.
Initializing generators
Once defined you don’t use generator functions like normal functions, instead you should initiate the generator.
|
|
This returns an iterator, which you use like so -
|
|
The above statement returns an object at the yield
statement within generator. So yield
is like a return
which is not a return
:)
|
|
The done
prop within the object indicates whether the generator has anything pending to do after the current yield
. Consider the below example -
|
|
yield
always returns the same object with same props.
You could technically do a return
within a generator function, but any yield
(or any other statement) will not execute after return
.
|
|
Loops in a generator
No one ever said, “let’s make life complicated”. But here we are.
yield
within a loop functions exactly as you would expect it to-
- function execution starts
- control goes into loop
- encounters
yield
- returns the object and goes into coma
- with the next
next()
control revives itself, finds itself in a loop, returns object and so on
|
|
Generator chains
yield
can call another generator. (And that’s really perfect since you can chain them to mess up one’s mind.)
|
|
Where could generators be useful?
All we described about generators is well and dandy, but there’s no hope for them until we find a use case (or two).
Here’s what smarter people are using generators for -
- Generate an (almost) infinite loop that increments once every call. This is useful for use cases like sliders that keep going round and round
- Use generators in place of recursion. We will get back to our favourite algorithms to generate Fibonacci series and such in a bit
- Throttle function calls. For example, call external API for one request at a time (and that’s a totally practical scenario. Stop smirking.)
- Use promises within generators to have async functions with throttling! See the previous point
- Store states during different instances of the program life cycle, suspend and carry on with the task later. For example, generating unique ids in our algorithm