E S 6 G E N E R AT O R S
R A M E S H N A I R H I D D E N TA O . C O M !A U G U S T 1 3 , 2 0 1 4 TA I P E I J A VA S C R I P T E N T H U S I A S T S
GENERATOR
A Generator generates values
…
Until no more values are available
S I M P L E G E N E R AT O R
var helloWorld = function*() {! yield 'hello';! yield 'world';!}
This function returns
a generatorThis generator “yields”
two strings
S T E P - B Y- S T E P
{ value: 'hello', done: false }
var gen = helloWorld();
var helloWorld = function*() {! yield 'hello';! yield 'world';!}
var value1 = gen.next();
console.log( value1 );
var value2 = gen.next();
console.log( value2 );{ value: 'world', done: false }
var value3 = gen.next();
console.log( value3 );{value: undefined, done: true}
F I B O N A C C I
var fib = function*() { let [prev, curr] = [0, 1]; for (;;) { [prev, curr] = [curr, prev + curr]; yield curr; }}
1, 2, 3, 5, 8, 13, 21, …
F O R - O F
var fib = function*() { let [prev, curr] = [0, 1]; for (;;) { [prev, curr] = [curr, prev + curr]; yield curr; }}!for (let n of fib()) { print(n); // 1, 2, 3, 5, 8, 13,…}
But yielding values isn’t that useful on its own
What if we could feed values back in?
F E E D I N G
{ value: 'hello', done: false }
var gen = helloWorld();
var value1 = gen.next();
console.log( value1 );
var value2 = gen.next(‘my’);
console.log( value2 );
{ value: ‘my world', done: false }
var helloWorld = function*() {! var v = yield 'hello';! yield v + ' world';!}
A yield is
synchronous
So what would happen if we yielded a Promise?
Y I E L D P R O M I S E S
Looks like a synchronous
call!
var gen = showUser();
var promise = gen.next().value;
promise.then(function(user) {!! gen.next(user);!});
var showUser = function*() {! var user = yield $.get(“/getUser?id=1”);! alert( user.name );!}
Y I E L D M A N Y P R O M I S E S
var gen = showStats();
var promise1 = gen.next().value;
promise1.then(function(user) {!!!!!});
var showStats = function*() {! var user = yield $.get(“/getUser?name=bob”);! var stats = yield $.get(“/stats/” + user.id);!! …!}
Repeats
! ! promise2.then(function(stats) {!! ! ! gen.next(stats);!! ! });!
var promise2 = gen.next(user).value;
C O - R O U T I N E S
var co = function(gen) {!! (var _next = function(res) {!! ! var yielded = gen.next(res);!! ! if (!yielded.done) {!! ! ! yielded.value.then(_next);!! ! }!! })();!}!!co(showStats());
var showStats = function*() {! var user = yield $.get(“/getUser?name=bob”);! var stats = yield $.get(“/stats/” + user.id);!! …!}
E R R O R S
var gen = showUser();
var promise = gen.next().value;
promise.then(function(user) {!! gen.next(user);!})
var showUser = function*() {!!!!!!}
! .catch(function(err) {! !! gen.throw(err);!! });
yield $.get(“/getUser?id=1”);try {!! ! !} catch (err) {! // do something!}!
Can yield inside here
G E N E R AT E D E R R O R S
var gen = showUser();
try {!! var promise = gen.next().value;!} catch (err) {! console.error(err);!}!
var showUser = function*() {! throw new Error(‘fail’);!}
B E T T E R C O - R O U T I N E
var co = function(gen) { (var _next = function(err, res) { try { var yld = null;! if (err) { yld = gen.throw(err); } else { yld = gen.next(res); }! if (!yld.done) { yld.value.then(function(result){ _next(null, result); }).catch(_next); } } catch (err) { console.error(err); } })();};
C O - R O U T I N E M O D U L E S
• Bluebird
• Promise.coroutine()
• Returns a Promise
• Lets you yield promises. Must configure it to support other item types.
• co
• co()!
• Accepts a callback
• Lets you yield promises, thunks, generators, generator functions
Faster for Promises
More flexible yielding
P R O M I S E S - > G E N E R AT O R S
var readFile = // returns a Promise!var main = function() { return readFile('file1') .then(function(contents) { console.log(contents); return readFile('file2'); }) .then(function(contents) { console.log(contents); })}!main().catch(…);
var readFile = // returns a Promise!var main = function*() { console.log(yield readFile('file1')); console.log(yield readFile('file2')); }!co(main)(…);
PA R A L L E L P R O C E S S I N G
var readFile = // returns a Promise!var main = function*() { var files = [ yield readFile('file1'), yield readFile('file2') ]; ... // do stuff with files}!co(main)();
var readFile = // returns a Promise!var main = function*() { var files = yield [ readFile('file1'), readFile('file2') ]; ... // do stuff with files}!co(main)();
sequential parallel
E X P R E S S - > K O A
var express = require('express');var app = express();!app.use(function(req, res, next){ res.send('Hello World');});!app.listen(3000);
var koa = require('koa');var app = koa();!app.use(function*(next){ this.body = 'Hello World';});!app.listen(3000);
Easier to control order of middleware execution…
K O A M I D D L E W A R E
• Waigo (waigojs.com) - web framework built around Koa
var koa = require('koa');var app = koa();!app.use(function*(next) { try { yield next; } catch (err) { // handle err }});!app.use(function*(next){ throw new Error('test');});
Execute rest of chain
A L S O C H E C K O U T…
• Iterators
• Simpler than generators
• Only return values, no feeding back in
• await!
• ES7 onwards
A N Y Q U E S T I O N S ?
Top Related