Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
What are Javascript Generators?

##what are generators##

  • They're pausable functions, pausable iterable functions, to be more precise
  • They're defined with the *
  • every time you yield a value, the function pauses until .next(modifiedYieldValue) is called
var myGen = function*() {
  var one = yield 1;
  var two = yield 2;
  var three = yield 3;
  console.log(one, two, three);
};

Define the generator and now run it

var gen = myGen(); //get the generator ready to run
//when you run next() on a generator, it runs until a yield, then waits until next() is called again
console.log(gen.next()); //{value:1, done: false}
console.log(gen.next()); //{value:2, done: false}
console.log(gen.next()); //{value:3, done: false}
console.log(gen.next()); //{value:undefined, done: true}
console.log(gen.next()); //errors because you can't call next() on a closed generator

The only problem here is that the final result it will log will be undefined, undefined, undefined Since yield sits in-between the yielded value and the rest of the function, we have to pass a value back in for it to get assigned to the variable.

console.log(gen.next()); //{value:1, done: false}
console.log(gen.next(1)); //{value:2, done: false}
console.log(gen.next(2)); //{value:3, done: false}
console.log(gen.next(3)); //{value:undefined, done: true}

So yippee, when do I ever have to yield numbers?
At first generators seem somewhat useless
The magic happens when smarter code wraps the generator
Here's a pretty dumb version of a smart wrapper (full code at bottom of gist)

function smartCode(generator) { //give me a generator function
  var gen = generator();//start up the generator
  var yieldedVal = gen.next().value;//get the first yielded value
  if(yieldedVal.then) { //is it a promise?
    //it's a promise!!!
    yieldedVal.then(gen.next);//wait for it to resolve, then pass the resolved value back in
  }
}

So, let's use a library with the smarts, like Bluebird, Co, Q

//Bluebird
Promise.coroutine(function* () {
  var tweets = yield $.get('tweets.json');
  console.log(tweets);
})();
//Bluebird runs the generator, notices yield is a promise
//so it waits on that promise, then passes it's value back to the generator when complete

//here, it runs them in sequence, waiting for each to complete before proceeding
Promise.coroutine(function* () {
  var tweets = yield $.get('tweets.json');
  var profile = yield $.get('profile.json');
  var friends = yield $.get('friends.json');
  console.log(tweets, profile, friends);
})();

AWESOME! If you want to run them at the same time, yield an object or an array.

//Bluebird needs a little pre-config to yield arrays, 
//add this setup codesomewhere in your app
Promise.coroutine.addYieldHandler(function(yieldedValue) {
    if (Array.isArray(yieldedValue)) return Promise.all(yieldedValue);
});


Promise.coroutine(function* () {
  var [tweets, profile] = yield [$.get('tweets.json'), yield $.get('profile.json')];
  console.log(tweets, profile);
})();

//or set it up to yield an object and run this

Promise.coroutine(function* () {
  var data = yield {
    tweets: $.get('tweets.json'),
    profile: yield $.get('profile.json')
  };
  console.log(data.tweets, data.profile);
})();

**Here's that full code of a generator wrapper

function smartCode(generator) {
  return function() {
    var gen = generator.apply(this,arguments);

    function handleNext(yielded) {
      if (yielded.done) return yielded.value; //return final return value

      if (yielded.value.then) {
        return yielded.value.then(function(res) {
          return handleNext(gen.next(res));
        }, function(err) {
          return handleNext(gen.throw(err));
        });
      } else {
        return handleNext(gen.next(yielded.value));
      }
    }
  }
}
@KarimLy

This comment has been minimized.

Copy link

KarimLy commented Mar 22, 2015

Clean and Awsome :)

@mzgupta

This comment has been minimized.

Copy link

mzgupta commented Apr 27, 2015

👍

@victorwpbastos

This comment has been minimized.

Copy link

victorwpbastos commented Sep 12, 2015

Which color scheme are you using on this vídeo?

@rehnen

This comment has been minimized.

Copy link

rehnen commented Dec 23, 2015

Looks like it's the rails cast theme, but I could be wrong.

@venugopalkathavate

This comment has been minimized.

Copy link

venugopalkathavate commented Feb 22, 2016

Awesome! Thanks for sharing.

@thegourav

This comment has been minimized.

Copy link

thegourav commented Apr 11, 2016

cool

@shamhub

This comment has been minimized.

Copy link

shamhub commented May 12, 2016

I think you missed, calling "handleNext(gen.next().value);"

@yashuvit89

This comment has been minimized.

Copy link

yashuvit89 commented Jul 28, 2016

Very helpful, one of the best generators tutorial. Thanks!

@jmitch0901

This comment has been minimized.

Copy link

jmitch0901 commented Aug 4, 2016

Awesome video and awesome gist! Just a quick question, I'm looking at where you placed the 'yield' statements.

In

  var data = yield {
    tweets: $.get('tweets.json'),
    profile: yield $.get('profile.json')
  };

and

var [tweets, profile] = yield [$.get('tweets.json'), yield $.get('profile.json')];

could you explain why the yields are placed where they are? This differs a little from the video.

@kailashyogeshwar85

This comment has been minimized.

Copy link

kailashyogeshwar85 commented Aug 25, 2016

Clean and nice explanation!! 👍

@vesakk

This comment has been minimized.

Copy link

vesakk commented Nov 5, 2016

Nice video!

These changes do the job...

var data = { tweets: yield $.get('tweets.json'), profile: yield $.get('profile.json') };

and

var [tweets, profile] = [yield $.get('tweets.json'), yield $.get('profile.json')];

@pigflymoon

This comment has been minimized.

Copy link

pigflymoon commented Nov 23, 2016

I try to run code in node.js, but when comes to $.get it comes error: Unhandled rejection TypeError: $.get is not a function
I have already require jquery library, but still didn't work.

@ghost

This comment has been minimized.

Copy link

ghost commented Mar 7, 2017

I feel like the async/await feature of ES2017 is the way to go:

The purpose of async/await functions are to simplify the behavior of using promises synchronously and to perform some behavior on a group of Promises. Just like Promises are similar to structured callbacks, async/await is similar to combining generators and promises.

@aaayumi

This comment has been minimized.

Copy link

aaayumi commented Oct 18, 2017

Thanks for the tutorial!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.