Skip to content

Instantly share code, notes, and snippets.

@learncodeacademy
Last active January 7, 2024 11:58
Show Gist options
  • Star 72 You must be signed in to star a gist
  • Fork 25 You must be signed in to fork a gist
  • Save learncodeacademy/bf04432597334190bef4 to your computer and use it in GitHub Desktop.
Save learncodeacademy/bf04432597334190bef4 to your computer and use it in GitHub Desktop.
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
Copy link

KarimLy commented Mar 22, 2015

Clean and Awsome :)

@mzgupta
Copy link

mzgupta commented Apr 27, 2015

👍

@victorwpbastos
Copy link

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

@rehnen
Copy link

rehnen commented Dec 23, 2015

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

@venugopalkathavate
Copy link

Awesome! Thanks for sharing.

@thegourav
Copy link

cool

@shamhub
Copy link

shamhub commented May 12, 2016

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

@yashuvit89
Copy link

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

@jmitch0901
Copy link

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
Copy link

Clean and nice explanation!! 👍

@vesakk
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
Copy link

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.

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
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