1. 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
2. G E N E R AT O R
A Generator generates values
…
Until no more values are available
3. 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
4. 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}
5. 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, …
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 values isn’t that useful on its own
What if we could feed values back in?
8. 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
10. 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 );!
}
11. 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;
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 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
14. 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’);!
}
15. 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);
}
})();
};
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 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)(…);
18. 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
19. 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…
20. 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
21. 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