Skip to content

Instantly share code, notes, and snippets.

@learncodeacademy
Last active January 7, 2024 11:58
Show Gist options
  • 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
OSZAR »