Asynchronous Adventures in JavaScript: Generators

Benjamin Diuguid
DailyJS
Published in
4 min readJun 13, 2016

What’s a Generator?

Generator are special functions that are new with ES6 / EcmaScript2015. Simply put, a Generator is a function whose execution is “pause-able and resume-able” meaning that it is not “run-to-completion”. This allows us to do some really cool things!

But why?

Generators allow us to do some really powerful things. Generators allow expensive computations to be simply split up and maintainable. They give us another way to write synchronous looking JavaScript which is actually asynchronous. Generators pave the way for the future of JavaScript with things like Async/Await.

Let’s learn with examples!

Defining Generators

In order to define a generator function we use the function* syntax, like so:

function* myGenerator1() {...}// orfunction * myGenerator2() {...}// orfunction *myGenerator3() {...}

Placement of the * does not matter. But for the purpose of this article I will be writing function* 😀.

The yield keyword

In order to “pause” the current execution and pass out a value to whatever invoked the generator function we will use the yield keyword, like so:

function* countingGenerator() {
yield 1;
yield 2;
yield 3;
}

Generator control-flow

There are 3 methods on the Generator’s prototype that allow us to control it.

  • Generator.prototype.next(value)
  • Generator.prototype.return(value)
  • Generator.prototype.throw(error)

Generator.prototype.next(value)

This will resume/start the generator, and its return value will be whatever the generator yields. After returning the yielded value* to it’s caller the generator function is “paused” and waits for it’s caller to invoke next() on the generator again. Once next() is called, the generator “resumes” where it last left off.

*: What is actually returned from the next() is an object with 2 properties, value, what is yielded from within the generator function, and done, a boolean describing if the generator is done or not. For example:

// Creating our Generator object.
var gen = countingGenerator();
var output1 = gen.next();
// output1: { value: 1, done: false }
var output2 = gen.next();
// output2: { value: 2, done: false }
var output3 = gen.next();
// output3: { value: 3, done: false }
// Notice here done is still false. We need to invoke it once more.var finalOutput = gen.next();
// finalOutput: { value: undefined, done: true }

Passing values into Generators

There are two ways to pass values into generators, through the constructor, and through control-flow methods. Parameters work exactly like normal functions. Control-flow methods like next() can receive a parameter which is passed into the place of where the generator has yielded. For example:

Generator.prototype.return(value)

The return method simply returns the given value, and terminates the generator.

Generator.prototype.throw(error)

The throw method simply passes in the error param to the resumed generator and then throws the error.

Infinite Generators

Since Generator functions have a “pause” and “resume” like nature, it is totally possible to create infinite generators.

Nested Generators / Generator Delegation

From inside one generator it is possible to call out to another generator, and thus delegating the yielded values to a different generator. This is done with the yield* keyword. Let’s see an example:

In the above example within our counter generator we are yield*-ing to our otherCounter which delegates to the otherCounter generator until the otherCounter is completely done, then counter will resume itself.

Fibonacci

Something Generators are useful is allowing us to pull values off of an infinite series whenever we want to, like the infinite generator that we looked at earlier. Here’s another example but with the Fibonacci sequence. If you don’t know what the Fibonacci sequence is, it’s rather simple. The first 2 numbers of the sequence are 1, and every term after it is the sum of the 2 previous numbers before it. Thus the beginning looks like this 1, 1, 2, 3, 5, 8, …

For more on Generators + Fibonacci check out Eric Elliott’s article!

Iterable Protocol

Another cool ES6/EcmaScript2015 feature is the Iterable Protocol. This protocol allows for JS objects to define an iteration behavior, which then things like map, reduce, and the for…of loop.

The Protocol states that the object must have a [Symbol.iterator] property which returns an iterator. An iterator is simply an object which has a method next which returns an object that has both a value property, and a done property. Sound familiar? The generator object that we receive from initializing a generator is an iterator! The for…of loop will iterate a generator to completion (so remember not to iterate infinitely over an infinite generator!). Thus we can iterate over the generator like so:

Further Real Examples

For some more real use cases of JavaScript Generators check these out:

Browser Support

At the time of writing this Generators are fully supported in Chrome 51+, Opera 38+, Edge 13+, Firefox 45+, the Safari Technical Preview, Node 6+ Traceur, and Babel. For a current look at the support check out the browser compatibility table.

But if you want to get started today you can use Babel to transpile your code! But you also may need to include the babel-polyfill at runtime.

Stay Tuned

Please join me in this series of Asynchronous Adventures where I will be highlighting how to handle asynchronous code in JavaScript from the basic stuff, to the advanced, fancy strategies.

This series covers in-depth analysis (with examples!) of the following JavaScript patterns:

Ben Diuguid is currently a student at the University of Florida. He is incredibly passionate about creating things, especially with JavaScript.

--

--