Javascript tips — Generators and Iterators

Leonardo Bruno Lima
3 min readMar 28, 2018

--

Photo by Ahmad Dirini on Unsplash

One of the most powerful features introduced in ES6 are generators. They allow you to define an iterative algorithm by writing a function which can maintain its own state, in fact it is a special type of function that works as a factory for iterators. (from MDN). They are also known as coroutines, which is the fundamental concept on which generators and iterators are built.

Before talk about generators, I we to understand what is iterators.

An object is considered an iterator when it knows how to access items from a collection one at a time, while keeping track of its current position within that sequence. In JavaScript an iterator is an object that provides a next() method which returns the next item in the sequence. This method returns an object with two properties: done and value.” (from MDN)

In other words an iterator is an object with a next method that returns { value, done}. An iterable is an object which has an internal method (obj[@@iterator]()) that returns an iterator.

Some built-in types, such as Array or Map, have a default iteration behavior

It seems quite confusing, but I will try to simplify with some examples. In this first one I’m going to create a interable (it should be able to produce any number of valid iterators) object using obj[@@iterator](). In fact all interable object must have a property with a Symbol.iterator key.

let myArr = ['a', 'b'];
let nextItem = myArr.next();
console.log(nextItem);

This code above produce an error: TypeError: arr.next is not a function. Alright, let’s fix it:

let arr = ['a', 'b'];
let iter = arr[Symbol.iterator]();
let nextItem = iter.next();
console.log(nextItem); // output { value: 'a', done: false }

Now we have an iterable object and everytime we call next() the output will be the next item in the sequence, which is an object with two properties: value and done. The value property is the value of the item, and done is a boolean value which is set to true when there are no more values to return.

let arr = ['a', 'b'];
let iter = arr[Symbol.iterator]();
let nextItem = iter.next();
console.log({ nextItem }); // output { value: 'a', done: false }
console.log({ nextItem }); // output { value: 'b', done: false }
console.log({ nextItem }); // output { value: undefined, done: true }

We can also create an iterator object by adding a method next on it.

function myIterator(array) {
let index = 0;
return {
next: function() {
return index < array.length ? { value: array[index++], done: false} : { value: undefined, done: true };
}
};
}
let it = myIterator([1, 2]);
console.log(it.next()); // output { value: 1, done: false }
console.log(it.next()); // output { value: 2, done: false }
console.log(it.next()); // output { value: undefined, done: true }

Ok, now we are ready to talk about generators. A generator have the ability halt execution of a function for an indefinite period of time when you call “yield” from inside a function and the code that invoked the generator can then control when the generator resumes or not.

In order to create a generator function we have to do two things: create a function with an asterisk (*) and use yield to return the next value. Let’s see an example:

function* myGenerator(array) {
let index = 0;
let len = array.length;
for(let x = 0; x < len; x++) {
yield array[x];
}
}
let it = myGenerator([1, 2]);
console.log(it.next()); // output { value: 1, done: false }
console.log(it.next()); // output { value: 2, done: false }
console.log(it.next()); // output { value: undefined, done: true }

That’s it, everytime the function reach “yield array[x]” it stops and wait for the next call. This feature is very useful and some cool javascript libraries use generator like Redux Saga among others.

Thanks!

--

--