However, this is just one use case (although a clever one) of using generators.

In this article, we will explore the strengths of using generators. There is a GitHub repository with the code samples we will go through that you can check out. You will also need Node 0.11.x (w/ the --harmony flag) or greater to run these examples. I personally use nvm for this.

What is a generator?

Generators are function executions that can be suspended and resumed at a later point; a lightweight coroutine. This behavior happens using special generator functions (noted by function* syntax) and a couple of new keywords (yield and yield*) which are only used in the context of a generator:

By invoking next() on the generator, it will execute up until it hits the next yield keyword or returns. Now we have console output.

Generators also have a built-in communication channel with yield:

function*channel(){varname=yield'hello, what is your name?'// [1]return'well hi there '+name}vargen=channel()console.log(gen.next().value)// hello, what is your name? [2]console.log(gen.next('billy'))// well hi there billy [3]

The yield keyword must always yield some value (even if its null). When execution resumes, it can optionally receive a value with the use of gen.next(value).

The object returned from gen.next() includes a value and a done property. The value property is the currently yielded (or returned) value from the generator. The done property is a Boolean indicating whether or not the generator has run to completion.

We can send a value into the generator using gen.next(value). The value is then assigned to name, in this example, as the generator resumes.

In addition to communicating values, you can also throw exceptions into generators with gen.throw(new Error(‘oh no’)).

What is yield* all about? The yield* keyword enables a generator function to yield to another generator function. This essentially gives control over to the other generator function until it has exhausted all of its yields and then it returns control to the originating generator. It should not be thought of as a way to do recursion with generators as I learned.

A common misconception

Now that I can suspend functions, I can run all this stuff in parallel right? No. _JavaScript is _still single-threaded, but now we have the ability to say STOP in the middle of a function.

If you are looking to bolster raw performance, generators may not be your ticket. Here’s a sample CPU intensive task, calculating a Fibonacci sequence number:

The results are pretty plain to see (higher is better). Generators aren’t doing anything magical for us here and there is a performance overhead:

results:regular1263899generator37541

Of course this is a trivial example, and performance will likely get better. You may find performance benefits using some of the upcoming examples, but generators are still not a magic bullet. You don’t divvy work up, you simply suspend it. Performance tends to be slightly slower using generators for asynchronous tasks, but they come with substantial benefits as we’ll see in a moment.

Where generators shine

Generators enable functionality that was either not possible before in JavaScript or was complicated. I find these cases the most compelling.

Lazy evaluation

Lazy evaluation is already possible with JavaScript using closure tricks and the like, but its greatly simplified now with yield. By suspending execution and resuming at will, we are able to pull values only when we need to. For instance, our above fibGen function was not fast per say but it was lazy. We pull new values whenever we ask for them.

Now we evaluate a Fibonacci stream lazily, asking it to return the first Fibonacci number after 5000:

for(varnumoffibGen()){if(num>5000)break}console.log(num)// 6765

That’s pretty cool.

Asynchronous control flow

Using generators for asynchronous control flow was first introduced by task.js (which no longer appears to exist) and popularized by frameworks like co and variouspromiselibraries. But how to does it actually work?

In Node land, everything is set up to work with callbacks. It is our lowest-level asynchronous abstraction. However, callbacks don’t work well with generators but yield will. If we invert how we have been using generators and use the built-in communications channel, we can write synchronous looking asynchronous code!

Summary

Generators are fun to play around with and I’m excited to see what other use cases we find for them. I would encourage you to play around with the GitHub repo. If there are other compelling use cases I didn’t mention, please let me know in the comments!

**Use StrongOps to Monitor Node Apps

**

Ready to start monitoring event loops, manage Node clusters and chase down memory leaks? We’ve made it easy to get started with StrongOps either locally or on your favorite cloud, with a simple npm install.

What’s next?

Ready to develop APIs in Node.js and get them connected to your data? Check out the Node.js LoopBack framework. We’ve made it easy to get started either locally or on your favorite cloud, with a simple npm install.