Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
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.
-...
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	
}	
...
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 cal...
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...
function addOne(num) {	
return num+1	
}	
!
var p = new Promise(	
function(res, rej) { res(0) })	
.then(addOne)	
.then(addO...
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()....
function* tick() {	
var x = yield	
var y = yield	
}	
!
var itr = tick()	
itr.next()	
itr.next(42) // x becomes 42	
itr.nex...
function* tick() {	
var num = 0	
while (!(yield num++));	
}	
!
var itr = tick()	
itr.next().value // 0	
itr.next().value /...
function* tick() {	
var num = 0	
while (!(yield num++));	
}	
!
var itr = tick()	
itr.next().value // 0	
itr.next().value /...
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....
function* delayThings() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
co...
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)	
co...
function* delayThings(resume) {	
var results1 = yield delay(1000, resume)	
console.log(results1)	
!
var results2 = yield d...
More
callbacks?
thunkify
// simplified from	
// https://github.com/visionmedia/node-thunkify	
!
function thunkify(fn){	
return function(){	
var arg...
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)	
}	
va...
function* delayThings() {	
var results1 = yield delay(1000)	
console.log(results1)	
!
var results2 = yield delay(1200)	
co...
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(...
var delayThings = co(function*() {	
var delays = [delay(1000), delay(1200)]	
var results = yield delays	
!
console.log(res...
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
Upcoming SlideShare
Loading in …5
×

Promises generatorscallbacks

591 views

Published on

Many developers new to Node.js struggle with writing asynchronous code in a clean, concise, easy to maintain manner. There are many strategies for managing and preventing 'callback hell' in Node.js. We'll walk through many of those strategies, from Promises to Generators to flow control libraries, and show that with a bit of forethought, writing asynchronous code in Javascript and Node.js can be easy and maintainable.

Published in: Technology
  • Be the first to comment

Promises generatorscallbacks

  1. 1. Promises, Generators & Callbacks! Oh my!
  2. 2. Writing asynchronous code is hard
  3. 3. asynchronous code is difficult to read
  4. 4. asynchronous code is difficult to write
  5. 5. asynchronous code is difficult to maintain
  6. 6. Mike Frey
  7. 7. Why is writing asynchronous code hard?
  8. 8. Composition
  9. 9. Patterns
  10. 10. Callbacks
  11. 11. Promises
  12. 12. Generators
  13. 13. Now entering Nerd War territory
  14. 14. Goals
  15. 15. Callbacks vs Promises vs Generators
  16. 16. Callbacks vs Promises vs Generators x x
  17. 17. No Winner
  18. 18. Unbiased
  19. 19. Informative
  20. 20. Callbacks
  21. 21. How do they work?
  22. 22. Continuation Passing
  23. 23. Pass a function to another function
  24. 24. Ask for work now Handle result later
  25. 25. askForWork(function(err, res) { // handle result later })
  26. 26. Where are they used?
  27. 27. Everywhere
  28. 28. Node.js core
  29. 29. User-land
  30. 30. Even Promises
  31. 31. Benefits
  32. 32. Simple. Easy to use. Prolific. Fast.
  33. 33. Problems
  34. 34. Error Handling
  35. 35. try{} catch(){}
  36. 36. try{} catch(){}
  37. 37. try { doWork(function(res) { // handle result }) } catch (err) { // handle error }
  38. 38. ! doWork(function(err, res) { // handle error // handle result }) ! !
  39. 39. Homework! read this: ! joyent.com/developers/ node/design/errors
  40. 40. Z͈A͡ ̼͔̭͖͕̲ L͝ ͙͖̱ G̠͍̤̠͕ O͢ ̬̫ Z͗̒͊̅ͫ̎ ̩̲̤͙̟ Ả͒͐̚ ̥̞̥͜ L̀͊ͬ͡ ̮̲Ğͥ̈ͩ̓͒ ͕̘͉ O͍̼̘͇͔̠͐ !̓̾̆ͪ͆̚͞
  41. 41. asynchronous or synchronous never both
  42. 42. Fix your API: process.nextTick() setImmediate()
  43. 43. Fix their API: dezalgo
  44. 44. Callback Hell
  45. 45. Composition problem
  46. 46. Now Later
  47. 47. Now Later Later-er
  48. 48. Now Later Later-er Later-er-er
  49. 49. Now Later Later-er Later-er-er Later-er-er-er
  50. 50. 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)
  51. 51. Now Later Later-er Later-er-er Later-er-er-er
  52. 52. Now Later Later-er Later-er-er Later-er-er-er
  53. 53. getA(function() { getB(function() { getC(function() { // do something }) }) })
  54. 54. function handleA() { getB(handleB) } function handleB() { getC(handleC) } function handleC() { // do something } getA(handleA)
  55. 55. async module
  56. 56. async.waterfall([ getA, getB, getC ], function(err, result) { // do something })
  57. 57. Callbacks ! Simple. Everywhere. Be careful.
  58. 58. Promises
  59. 59. How do they work?
  60. 60. Eventual Result
  61. 61. .then()
  62. 62. var promise = doSomething() promise.then( function (result) { // success callback }, function (error) { // error callback })
  63. 63. Now Later success Later failure
  64. 64. Where are they used?
  65. 65. jQuery AngularJS Ember User-land
  66. 66. Chrome 32 Firefox 29 Opera 19 Node.js 0.11.13
  67. 67. Benefits
  68. 68. Composition: Chaining & Error handling
  69. 69. .then() .then() .then()
  70. 70. Now Later success Later-er success Later-er-er success Later-er-er-er success
  71. 71. function addOne(num) { return new Promise( function(resolve, reject) { resolve(num+1) }) } ! addOne(0) .then(addOne) .then(addOne) .then(addOne) .then(console.log)
  72. 72. function addOne(num) { return num+1 } ! var p = new Promise( function(res, rej) { res(0) }) .then(addOne) .then(addOne) .then(addOne) .then(console.log)
  73. 73. Rejections bubble
  74. 74. Errors bubble
  75. 75. Now Later success Later-er success Later-er-er success Any failure
  76. 76. getSpeakers('MidwestJS') .then(getGithubUsers) .then(getPublicRepos) .then(listRepos, handleError)
  77. 77. Problems
  78. 78. Slow
  79. 79. Slow
  80. 80. Incompatible Proposals & Implementations
  81. 81. jQuery vs everyone else
  82. 82. Promises ! Composable. Eventual Result.
  83. 83. Generators
  84. 84. What are they?
  85. 85. How do they work?
  86. 86. function*
  87. 87. function* tick() { ! ! } ! ! ! !
  88. 88. function* tick() { ! ! } ! var itr = tick() ! !
  89. 89. function* tick() { ! ! } ! var itr = tick() itr.next() !
  90. 90. function* tick() { yield 42 ! } ! var itr = tick() itr.next().value // 42 !
  91. 91. yield
  92. 92. function* tick() { yield 42 yield 43 } ! var itr = tick() itr.next().value // 42 itr.next().value // 43 itr.next().done // true
  93. 93. 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
  94. 94. function* tick() { var num = 0 while (!(yield num++)); } ! var itr = tick() itr.next().value // 0 itr.next().value // 1 itr.next().value // 2
  95. 95. function* tick() { var num = 0 while (!(yield num++)); } ! var itr = tick() itr.next().value // 0 itr.next().value // 1 itr.next(true).done // true
  96. 96. Replacing callbacks
  97. 97. function delay(time, callback) { setTimeout(function() { callback('Slept for ' + time) }, time) }
  98. 98. function delayThings() { delay(1000, function(result1) { console.log(result1) delay(1200, function(result2) { console.log(result2) }) }) } // Slept for 1000 // Slept for 1200
  99. 99. function* delayThings() { var results1 = yield delay(1000) console.log(results1) ! var results2 = yield delay(1200) console.log(results2) }
  100. 100. function run(generator) { function resume(value) { itr.next(value) } var itr = generator(resume) itr.next() }
  101. 101. function* delayThings() { var results1 = yield delay(1000) console.log(results1) ! var results2 = yield delay(1200) console.log(results2) } !
  102. 102. function* delayThings(resume) { var results1 = yield delay(1000, resume) console.log(results1) ! var results2 = yield delay(1200, resume) console.log(results2) } ! run(delayThings)
  103. 103. More callbacks?
  104. 104. thunkify
  105. 105. // 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) } } }
  106. 106. delay = thunkify(delay) ! var thunk = delay(1000) ! thunk(function(result) { console.log(result) })
  107. 107. function run(generator) { function resume(value) { itr.next(value) } var itr = generator(resume) itr.next() } !
  108. 108. function run(generator) { function resume(ret) { var obj = itr.next(ret) if (obj.done) return obj.value(resume) } var itr = generator() resume() }
  109. 109. function* delayThings() { var results1 = yield delay(1000) console.log(results1) ! var results2 = yield delay(1200) console.log(results2) } ! run(delayThings)
  110. 110. yield Now Later
  111. 111. yield Now yield Later Later-er
  112. 112. yield Now yield Later yield Later-er Later-er-er
  113. 113. yield Now yield Later yield Later-er yield Later-er-er Later-er-er-er …
  114. 114. co
  115. 115. var delayThings = co(function*() { var results1 = yield delay(1000) console.log(results1) ! var results2 = yield delay(1200) console.log(results2) }) ! delayThings()
  116. 116. var delayThings = co(function*() { var delays = [delay(1000), delay(1200)] var results = yield delays ! console.log(results[0]) console.log(results[1]) }) ! delayThings()
  117. 117. Where are they used?
  118. 118. co koa User-land
  119. 119. Firefox 31 Chrome (flag) Node.js v0.11.10 (flag) Opera (flag)
  120. 120. Benefits
  121. 121. Feels synchronous
  122. 122. try{} catch(){}
  123. 123. New cool
  124. 124. Problems
  125. 125. Support
  126. 126. regenerator facebook.github.io/regenerator/
  127. 127. traceur github.com/google/traceur-compiler
  128. 128. Immature implementations
  129. 129. Generators ! yield statement. Pausable function*. Built for iterators.
  130. 130. Writing asynchronous code is hard
  131. 131. But it doesn’t have to be!
  132. 132. Call to action
  133. 133. Explore
  134. 134. Streams http://nodestreams.com http://highlandjs.org
  135. 135. Thank you!
  136. 136. Questions? ! References available here: github.com/mikefrey/cpg-talk

×