JavaScript provides several ways of iterating over a collection, from simple for loops to map() and filter(). Iterators and generators bring the concept of iteration directly into the core language and provide a mechanism for customizing the behaviour of ‘for...of loops’. Iterators and generators usually come as a secondary thought when writing code, but if you can take a few minutes to think about how to use them to simplify your code, they'll save you from a lot of debugging and complexities.
Iterators
When we have an array, we typically use the ‘for loop’ to iterate over its element.
ES6 introduced a new loop construct called ‘for...of’ to eliminate the standard loop’s complexity
The ‘for...of the loop’ can create a loop over any iterable object, not just an array.
Iterable values in JavaScript
The following values are iterable –
Plain objects are not iterable and hence the 'for...of' uses the Symbol.iterator.
Symbol.iterator
The Symbol.iterator is a special-purpose symbol made especially for accessing an object's internal iterator. So, you could use it to retrieve a function that iterates over an array object, like so –
Generators
Generator functions once called, returns the Generator object, which holds the entire Generator iterable and can be iterated using next() method. Every next() call on the generator executes every line of code until it encounters the next yield and suspends its execution temporarily.
Generators are a special type of function in JavaScript that can pause and resume state. A Generator function returns an iterator, which can be used to stop the function in the middle, do something, and then resume it whenever.
Fun Fact – async/await can be based on generators
Generator functions/yield and Async functions/await can both be used to write asynchronous code that 'waits', which means code that looks as if it was synchronous, even though it is asynchronous. ... An async function can be decomposed into a generator and promise implementation which is good to know stuff.
Generator functions are written using the function* syntax –
Additionally, generators can also receive input and send output via yield. In short, a generator appears to be a function but it behaves like an iterator.
A generator is a function that returns an object on which you can call next(). Every invocation of next() will return an object of shape —
Here are some other common definitions of generators
Output
Passing a function to yield
Apart from returning values, the yield can also call a function –
Output
Delegating to another generator or iterable using yield* expression
Output
Let’s see an example of fetching a single value from an API
As a Title –
Output
Advantages of Generators
This is an evaluation model that delays the evaluation of an expression until its value is needed. That is, if the value is not needed, it will not exist. It is calculated on demand.
A direct outcome of Lazy Evaluation is that generators are memory efficient.
The only values generated are those that are needed. With normal functions, all the values must be pre-generated and kept around case they need to be used later.
Conclusion
We have learned the following things about iterators and generators –