##what are generators##
- They're pausable functions, pausable iterable objects, to be more precise
- They're defined with the *
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 generatorThe 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 the new yielded 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? Seems silly The magic happens when smarter code wraps the generator Here's a pretty dumb version of a smart wrapper
function smartCode(generator) { //give me a generator function
var gen = generator();//start up the generator
var yieldedVal = gen.next();//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, FYI
Promise.coroutine(function* () {
var data = yield {
tweets: $.get('tweets.json'),
profile: yield $.get('profile.json')
};
console.log(data.tweets, data.profile);
})();
Promise.coroutine(function* () {
var [tweets, profile] = yield [$.get('tweets.json'), yield $.get('profile.json')];
console.log(tweets, profile);
})();