What are generators and how can I use them?
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
- We used a keyword
- Initiated the function
- Called the generator function multiple times - with each time stopping at the next
yieldto return a value
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.
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.
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
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
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
- returns the object and goes into coma
- with the next
next()control revives itself, finds itself in a loop, returns object and so on
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