KEMBAR78
Javascript ES6 generators | PDF
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
G E N E R AT O R
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 WA 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 ?

Javascript ES6 generators

  • 1.
    E S 6G 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
  • 2.
    G E NE R AT O R A Generator generates values … Until no more values are available
  • 3.
    S I MP 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
  • 4.
    S T EP - 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}
  • 5.
    F I BO 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, …
  • 6.
    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,… }
  • 7.
    But yielding valuesisn’t that useful on its own What if we could feed values back in?
  • 8.
    F E ED 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
  • 9.
    So what wouldhappen if we yielded a Promise?
  • 10.
    Y I EL 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 );! }
  • 11.
    Y I EL 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;
  • 12.
    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);! ! …! }
  • 13.
    E R RO 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
  • 14.
    G E NE 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’);! }
  • 15.
    B E TT 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); } })(); };
  • 16.
    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
  • 17.
    P R OM 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)(…);
  • 18.
    PA R AL 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
  • 19.
    E X PR 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…
  • 20.
    K O AM I D D L E WA 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
  • 21.
    A L SO C H E C K O U T… • Iterators • Simpler than generators • Only return values, no feeding back in • await! • ES7 onwards
  • 22.
    A N YQ U E S T I O N S ?