Promises,
Generators &
Callbacks!
Oh my!
Writing
asynchronous
code is hard
asynchronous
code is difficult to
read
asynchronous
code is difficult to
write
asynchronous
code is difficult to
maintain
Mike Frey
Why is writing
asynchronous
code hard?
Composition
Patterns
Callbacks
Promises
Generators
Now entering
Nerd War
territory
Goals
Callbacks
vs
Promises
vs
Generators
Callbacks
vs
Promises
vs
Generators
x
x
No
Winner
Unbiased
Informative
Callbacks
How do
they work?
Continuation
Passing
Pass a
function
to another
function
Ask for work now
Handle result later
askForWork(function(err, res) {	
// handle result later	
})
Where are
they used?
Everywhere
Node.js core
User-land
Even
Promises
Benefits
Simple.
Easy to use.
Prolific.
Fast.
Problems
Error
Handling
try{} 	
catch(){}
try{} 	
catch(){}
try {	
doWork(function(res) {	
// handle result	
})	
}	
catch (err) {	
// handle error 	
}
!
doWork(function(err, res) {	
// handle error	
// handle result	
})	
!
!
Homework!
read this:
!
joyent.com/developers/
node/design/errors
Z͈A͡ ̼͔̭͖͕̲
L͝ ͙͖̱
G̠͍̤̠͕
O͢ ̬̫
Z͗̒͊̅ͫ̎
̩̲̤͙̟
Ả͒͐̚
̥̞̥͜
L̀͊ͬ͡
̮̲Ğͥ̈ͩ̓͒
͕̘͉
O͍̼̘͇͔̠͐
!̓̾̆ͪ͆̚͞
asynchronous
or
synchronous
never both
Fix your API:
process.nextTick()
setImmediate()
Fix their API:
dezalgo
Callback
Hell
Composition
problem
Now
Later
Now
Later
Later-er
Now
Later
Later-er
Later-er-er
Now
Later
Later-er
Later-er-er
Later-er-er-er
There’s nothing forcing
you to write ten levels of
nested callbacks, but
the pattern does make
it easy for you to do so.
- Raymond Julin (paraphrased)
Now
Later
Later-er
Later-er-er
Later-er-er-er
Now
Later
Later-er
Later-er-er
Later-er-er-er
getA(function() {	
getB(function() {	
getC(function() {	
// do something	
})	
})	
})
function handleA() {	
getB(handleB)	
}	
function handleB() {	
getC(handleC)	
}	
function handleC() {	
// do something	
}	
getA(handleA)
async
module
async.waterfall([	
getA,	
getB,	
getC	
], 	
function(err, result) {	
// do something	
})
Callbacks
!
Simple.
Everywhere.
Be careful.
Promises
How do
they work?
Eventual
Result
.then()
var promise = doSomething()	
promise.then(	
function (result) {	
// success callback	
},	
function (error) {	
// error callback	
})
Now
Later success
Later failure
Where are
they used?
jQuery
AngularJS
Ember
User-land
Chrome 32
Firefox 29
Opera 19
Node.js 0.11.13
Benefits
Composition:
Chaining &
Error handling
.then()
.then()
.then()
Now
Later success
Later-er success
Later-er-er success
Later-er-er-er success
function addOne(num) {	
return new Promise(	
function(resolve, reject) {	
resolve(num+1)	
})	
}	
!
addOne(0)	
.then(addOne)	
.then(addOne)	
.then(addOne)	
.then(console.log)
function addOne(num) {	
return num+1	
}	
!
var p = new Promise(	
function(res, rej) { res(0) })	
.then(addOne)	
.then(addOne)	
.then(addOne)	
.then(console.log)
Rejections
bubble
Errors
bubble
Now
Later success
Later-er success
Later-er-er success
Any failure
getSpeakers('MidwestJS')	
.then(getGithubUsers)	
.then(getPublicRepos)	
.then(listRepos,	
handleError)
Problems
Slow
Slow
Incompatible
Proposals &
Implementations
jQuery
vs
everyone else
Promises
!
Composable.
Eventual Result.
Generators
What are
they?
How do
they work?
function*
function* tick() {	
!
!
}	
!
!
!
!
function* tick() {	
!
!
}	
!
var itr = tick()	
!
!
function* tick() {	
!
!
}	
!
var itr = tick()	
itr.next()	
!
function* tick() {	
yield 42	
!
}	
!
var itr = tick()	
itr.next().value // 42	
!
yield
function* tick() {	
yield 42	
yield 43	
}	
!
var itr = tick()	
itr.next().value // 42	
itr.next().value // 43	
itr.next().done // true
function* tick() {	
var x = yield	
var y = yield	
}	
!
var itr = tick()	
itr.next()	
itr.next(42) // x becomes 42	
itr.next(43) // y becomes 43
function* tick() {	
var num = 0	
while (!(yield num++));	
}	
!
var itr = tick()	
itr.next().value // 0	
itr.next().value // 1	
itr.next().value // 2
function* tick() {	
var num = 0	
while (!(yield num++));	
}	
!
var itr = tick()	
itr.next().value // 0	
itr.next().value // 1	
itr.next(true).done // true
Replacing
callbacks
function delay(time, callback) {	
setTimeout(function() {	
callback('Slept for ' + time)	
}, time)	
}
function delayThings() {	
delay(1000, function(result1) {	
console.log(result1)	
delay(1200, function(result2) {	
console.log(result2)	
})	
})	
}	
// Slept for 1000	
// Slept for 1200
function* delayThings() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
console.log(results2)	
}
function run(generator) {	
function resume(value) {	
itr.next(value)	
}	
var itr = generator(resume)	
itr.next()	
}
function* delayThings() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
console.log(results2)	
}	
!
function* delayThings(resume) {	
var results1 = yield delay(1000, resume)	
console.log(results1)	
!
var results2 = yield delay(1200, resume)	
console.log(results2)	
}	
!
run(delayThings)
More
callbacks?
thunkify
// simplified from	
// https://github.com/visionmedia/node-thunkify	
!
function thunkify(fn){	
return function(){	
var args = Array.prototype.slice.call(arguments)	
return function(done){	
args.push(function(){	
done.apply(null, arguments)	
})	
fn.apply(null, args)	
}	
}	
}
delay = thunkify(delay)	
!
var thunk = delay(1000)	
!
thunk(function(result) {	
console.log(result)	
})
function run(generator) {	
function resume(value) {	
itr.next(value)	
}	
var itr = generator(resume)	
itr.next()	
}	
!
function run(generator) {	
function resume(ret) {	
var obj = itr.next(ret)	
if (obj.done) return	
obj.value(resume)	
}	
var itr = generator()	
resume()	
}
function* delayThings() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
console.log(results2)	
}	
!
run(delayThings)
yield Now
Later
yield Now
yield Later
Later-er
yield Now
yield Later
yield Later-er
Later-er-er
yield Now
yield Later
yield Later-er
yield Later-er-er
Later-er-er-er
…
co
var delayThings = co(function*() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
console.log(results2)	
})	
!
delayThings()
var delayThings = co(function*() {	
var delays = [delay(1000), delay(1200)]	
var results = yield delays	
!
console.log(results[0])	
console.log(results[1])	
})	
!
delayThings()
Where are
they used?
co
koa
User-land
Firefox 31
Chrome (flag)
Node.js v0.11.10 (flag)
Opera (flag)
Benefits
Feels
synchronous
try{}
catch(){}
New cool
Problems
Support
regenerator
facebook.github.io/regenerator/
traceur
github.com/google/traceur-compiler
Immature
implementations
Generators
!
yield statement.
Pausable function*.
Built for iterators.
Writing
asynchronous
code is hard
But it
doesn’t
have to be!
Call to
action
Explore
Streams
http://nodestreams.com
http://highlandjs.org
Thank you!
Questions?
!
References available here:
github.com/mikefrey/cpg-talk

Promises generatorscallbacks