AddThis

Thursday, October 30, 2014

JavaScript Generators

Intro

One of the things people are really excited about that is coming in EcmaScript6 (Harmony) are generators.  There is a lot of writing out there today on generators but for the most part, I found the writing to be too quick to skip over the fundamental question of what they are.  Basically I was looking for a tl;dr.  Cuz ain't nobody got time for that.






Definition

I actually really like Mozilla's definition.  Short and sweet:
"Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances."

Allow me to paraphrase:
tl;dr Generators are special functions that save their variable state between calls.






Example

Now that you got the basic idea, let's look at an example.

First notice that the function definition has an asterick *.

//will double the number passed in
function* doubler(i){
  var doubled = i;
  while(true){
    doubled *= 2;
    yield doubled;
  }
}


Next notice the yield keyword.  We'll come back to that.  Let's take a look at the usage.

var gen = doubler(1);


The interesting thing is that calling doubler doesn't actually invoke the function.  A special object called an iterator is returned.  So gen holds an iterator, so lets see how to use that:

var result = gen.next();


Calling the next method on the iterator actually runs the doubler function, but stops when it hits the keyword yield (told you we'd come back to it).  And whatever you pass to yield (in this case the variable doubled), the iterator returns that.  So line by line:

var doubled = i;
//remember from above that i is 1, var gen = doubler(1);

while(true) {
 //nothing says that the iterator has to terminate. 
 //it can go on forever like this one does

  doubled *= 2;
  //doubled was 1, now its 2, b/c well 1*2 is 2

  yield doubled;
  //the iterator will stop here for now and return 2
}


So there you go, result should be 2.  Conceptually, that's sufficient to say, but in practice, the iterator takes 'doubled' and wraps it inside of a result object.  The result object has two attributes:

1.  The 'value' attribute which holds the value of 'doubled'.
2.  An attribute called 'done' that tells us if the iterator is done, which of course it isn't b/c we have a forever loop there.

{value: 2, done: false}


So what happens if we call next() again?

result = gen.next();


If you said

{value: 4, done: false}


Then congrats!  This is just the surface of how we can use generators, but once you understand this, the rest is cake.




Further Reading

If you would like to dive deeper into generators, check out this guide.  It's pretty detailed and explains some of the many ways you can use generators.

I also recommend the Mozilla documentation:




Using It Today

Great, you love generators now and want to use them today.  Unfortunately, the spec isn't officially finalized yet and not all browsers support it today.  To see who supports it, check out this table here.

You could also use transpilers like Traceur to turn it into regular JavaScript.

Or you can do what I did, and that's to use node.  Let's say all your JavaScript code is in generators.js.  Then just install node and run:

node --harmony generators.js