the strange world of javascript and all its little asynchronous beasts
DESCRIPTION
Javascript is a wonderland populated by all kinds of exotic beasts. Callbacks, events, promises, functional programming, reactive programming, streams, generators are all part of this incredible asynchronous bestiary. We’re talking of insidious or even ferocious things, a great danger to the unwary programmer. Let’s look at them, learn from them, tame them and finally put them to our own advantage. Let’s stop Javascript from being an unfamiliar place and make it feel much more like home. Talk I held on 14/05/2014 at JsDay, Verona, Italy. Corrected slides. http://2014.jsday.it/talk/the-strange-world-of-javascript-and-all-its-little-asynchronous-beasts/ Feedback! https://joind.in/talk/view/11280 Follow me on Twitter! https://twitter.com/federicogalassiTRANSCRIPT
![Page 1: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/1.jpg)
The strange world of javascript and
all its littleasynchronous beasts
![Page 2: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/2.jpg)
Federico Galassi
@federicogalassi
http://federico.galassi.net
![Page 3: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/3.jpg)
I wrote this
http://www.jsbestpractices.it
![Page 4: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/4.jpg)
asynchronous
non-blocking
event-driven
confused!
callbacks...
![Page 5: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/5.jpg)
Rob Pike
Concurrencyis not
Parallelism
http://vimeo.com/49718712
![Page 6: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/6.jpg)
Rob Pike
Concurrency is a way tostructure a program bybreaking it into piecesthat can be executedindependently
![Page 7: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/7.jpg)
Javascriptis
concurrent !
![Page 8: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/8.jpg)
All in one threadNo it’s not.
Joe Armstrong
![Page 9: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/9.jpg)
I want to disappear
![Page 10: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/10.jpg)
Unlike utopian worlds...I live in
synchronousbliss!!
![Page 11: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/11.jpg)
Javascriptcan learn from
concurrentlanguages
![Page 12: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/12.jpg)
Go has gophers
![Page 13: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/13.jpg)
Gophers block onchannels
c := make(chan int)go func() { for i := 0; i < 100; i++ { c <- i }}()go func() { for { i := <- c fmt.Println(i) }}()
![Page 14: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/14.jpg)
Erlang has actors
![Page 15: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/15.jpg)
Actors block onreceive
P = fun Producer(N, C) when N < 100 -> C ! {N, self()}, Producer(N + 1, C)end.
C = fun Consumer() -> receive {N, Pid} -> io:format("received ~p from ~p~n", [N, Pid]), Consumer() endend.
Cons = spawn(C).P(0, Cons).
![Page 16: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/16.jpg)
The gold rule is
![Page 17: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/17.jpg)
You must be able toBLOCK
![Page 18: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/18.jpg)
Javascriptwas
concurrentby
necessity
Brendan Eich
![Page 19: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/19.jpg)
Key pressed
Do nothing Button.onclickExec.
Eventqueue
TimeKey pressed
the Event Loop
ClickKey pressed
Click
User click
button.onclick = function() { element.style.color = "red"})
![Page 20: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/20.jpg)
Continuationpassing style
refuel()startEngine()takeOff()land()// ... done
![Page 21: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/21.jpg)
Continuationpassing style
refuel(function() { startEngine() takeOff() land() // ... done})
![Page 22: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/22.jpg)
Continuationpassing style
refuel(function() { startEngine(function() { takeOff() land() // ... done })})
![Page 23: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/23.jpg)
Continuationpassing style
refuel(function() { startEngine(function() { takeOff(function() { land() // ... done }) })})
![Page 24: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/24.jpg)
The Pyramid of Doom
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
![Page 25: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/25.jpg)
The Pyramid of Doom
![Page 26: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/26.jpg)
Loss of control flow
images.forEach(function(url) { var image = download(url) image.show()})
![Page 27: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/27.jpg)
Loss of control flow
images.forEach(function(url) { download(url, function(image) { image.show() })})
![Page 28: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/28.jpg)
Loss of control flow
var showImages = function(images, callback) { var url = images.shift() if (url) { download(url, function(image) { image.show() showImages(images, callback) }) } else { callback() }})
![Page 29: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/29.jpg)
Loss of control flow
![Page 30: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/30.jpg)
Loss of error handling
try { download(url, function(image) { image.show() })} catch(e) { // never executed!! console.log("Cannot show image")}
![Page 31: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/31.jpg)
Sync/Async Ambiguity
try { // is download Asynchronous?!?! download(url, function(image) { image.show() })} catch(e) { // never executed!! console.log("Cannot show image")}
![Page 32: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/32.jpg)
Sync/Async Ambiguity
try { // Is download Asynchronous?!?! download(url, function(image) { image.show() })} catch(e) { // never executed!! console.log("Cannot show image")}
![Page 33: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/33.jpg)
It’s not really like this
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
![Page 34: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/34.jpg)
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
More like this
// ... After a while ...
![Page 35: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/35.jpg)
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
Where do we land?
// ... After a while ...
???
???
???
![Page 36: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/36.jpg)
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
What do we know?
![Page 37: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/37.jpg)
When an async call completesI’m time warped back in timeto the callback code then backto wherever I came from.I find this very difficult tounderstand
http://joearms.github.io/2013/04/02/Red-and-Green-Callbacks.html
Joe Armstrong
![Page 38: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/38.jpg)
It’s even worse, every javascript programmer who has a concurrent problem to solve must invent their own concurrency model
Joe Armstrong
http://joearms.github.io/2013/04/02/Red-and-Green-Callbacks.html
![Page 39: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/39.jpg)
In javascript youCAN’T BLOCK
![Page 40: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/40.jpg)
ES6 to rescue us!
![Page 41: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/41.jpg)
with Generators
function* upTo(end) { for (var i = 0; i <= end; i++) { yield i }}
![Page 42: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/42.jpg)
Generators make iterators
var counter = upTo(100)
counter.next() // => Object {value: 0, done: false}counter.next() // => Object {value: 1, done: false}counter.next() // => Object {value: 2, done: false}
// ...
counter.next() // => Object {value: 99, done: false}counter.next() // => Object {value: undefined, done: true}
![Page 43: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/43.jpg)
function* upTo(end) { for (var i = 0; i <= end; i++) {
yield i
}}
Generators rememberexecution stack
restartsHere!
![Page 44: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/44.jpg)
Yieldcan receive values
function* upTo(end) { for (var i = 0; i <= end; i++) { var newI = yield i if (newI) i = newI }}
var counter = upTo(100)
counter.next() // => Object {value: 0, done: false}counter.next() // => Object {value: 1, done: false}counter.next(10) // => Object {value: 11, done: false}counter.next() // => Object {value: 12, done: false}
![Page 45: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/45.jpg)
Yieldcan receive errors
function* upTo(end) { for (var i = 0; i <= end; i++) { yield i }}
var counter = upTo(100)
counter.next() // => Object {value: 0, done: false}counter.next() // => Object {value: 1, done: false}counter.throw(new Error("argh")) // => Error: argh
![Page 46: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/46.jpg)
Yes, this isBlocking!!
![Page 47: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/47.jpg)
Blocking for sequence
async(function*() { yield refuel() yield startEngine() yield takeOff() yield land()})
![Page 48: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/48.jpg)
Blocking forcontrol flow
async(function*() { images.forEach(function(url) { var image = yield download(url) image.show() })})
![Page 49: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/49.jpg)
Blocking forerror handling
async(function*() { try { var image = yield download(url) image.show() } catch(e) { console.log("Cannot show image") }})
![Page 50: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/50.jpg)
What is async() ?
https://github.com/kriskowal/q/tree/v1/examples/async-generators
http://pag.forbeslindesay.co.uk/#/22
// Implementation by Lindesay Forbesfunction async(makeGenerator){ return function (){ var generator = makeGenerator.apply(this, arguments) function handle(result){ // { done: [Boolean], value: [Object] } if (result.done) return result.value return result.value.then(function (res){ return handle(generator.next(res)) }, function (err){ return handle(generator.throw(err)) }) } return handle(generator.next()) }}
![Page 51: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/51.jpg)
async is too complex
![Page 52: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/52.jpg)
Generators support
http://kangax.github.io/compat-table/es6/#Generators_(yield)
![Page 53: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/53.jpg)
I think this is the way
![Page 54: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/54.jpg)
or there is the dark way
![Page 55: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/55.jpg)
inventing your own concurrency
modelJoe Armstrong
![Page 56: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/56.jpg)
it will be leaky
![Page 57: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/57.jpg)
Still you can buildyour little paradise
![Page 58: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/58.jpg)
Functional compositionwith Async.js
https://github.com/caolan/async
CaolanMcmahon
![Page 59: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/59.jpg)
functions in Async.js
function(callback) { download(url, function() { callback() })}
![Page 60: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/60.jpg)
error handling the node.js way
function(callback) { download(url, { success: function(result) { // success, null error then result callback(null, result) }, error: function(err) { // failure, error and no result callback(err) } })}
![Page 61: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/61.jpg)
The Pyramid of Doom
refuel(function() { startEngine(function() { takeOff(function() { land(function() { // ... done }) }) })})
![Page 62: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/62.jpg)
Demolished withsequential composition
async.series([ refuel, startEngine, takeOff, land], function(err, result) { // done!})
![Page 63: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/63.jpg)
Pretty control flow
images.forEach(function(url) { download(url, function(image) { image.show() })})
![Page 64: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/64.jpg)
Prettyfunctional composition
async.map(images, function(callback) { download(url, function(image) { callback(null, image) })}, function(err, results) { results.forEach(function(image) { image.show() })})
![Page 65: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/65.jpg)
Composition of composition
async.waterfall([ function(callback) { async.map(files, fs.readFile, callback) }, function(contents, callback) { async.map(contents, countWords, callback) }, function(countedWords, callback) { async.reduce(countedWords, 0, sum, callback) },], function(err, totalWords) { // The number of words in files is totalWords})
![Page 66: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/66.jpg)
Composition of composition is the
real power
![Page 67: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/67.jpg)
Functionallack of state is the
weakness
![Page 68: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/68.jpg)
No decoupling
async.series([ refuel, startEngine, takeOff, land], function(err, result) { // done!})
call start
callbackbinding
![Page 69: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/69.jpg)
async.series([ refuel, startEngine, takeOff, land], function(err, result) { // done! share = result})
globalvariableto share
No decoupling
![Page 70: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/70.jpg)
async.series([ refuel, startEngine, takeOff, land], function(err, result) { // done! logger.log(err) stats.update(result) spinner.hide()})
divergentchange
No decoupling
![Page 71: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/71.jpg)
No decouplingis bad
![Page 72: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/72.jpg)
We need first classasynchronous calls
to keep the stateof the computation
![Page 73: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/73.jpg)
OOP compositionwith Promises
![Page 74: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/74.jpg)
Promise is an objectrepresenting an
async computation
var promise = new Promise(function(resolve, reject) { // do asynchronous computation ... if (succeeded) { resolve(result) } else { reject(new Error(err)) }})
http://promisesaplus.com
https://www.promisejs.org/
![Page 75: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/75.jpg)
The computation will eventually produce
an outcome
var promise = new Promise(function(resolve, reject) { // do asynchronous computation ... if (succeeded) { resolve(result) } else { reject(new Error(err)) }})
http://promisesaplus.com
https://www.promisejs.org/
![Page 76: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/76.jpg)
Promise hasstates
var promise = new Promise(function(resolve, reject) { // do asynchronous computation ... if (succeeded) { resolve(result) } else { reject(new Error(err)) }})
pending
fulfilled
rejected
![Page 77: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/77.jpg)
Promise is thenable
promise.then( function(result) { // promise fulfilled }, function(err) { // promise rejected })
![Page 78: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/78.jpg)
Promise remembers its final state
promise // after some time ... .then(function(result) { // fulfilled, result is "hello" })
// after a while ...
promise .then(function(result) { // fulfilled, result still "hello" })
![Page 79: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/79.jpg)
Promise remembers its final state
promise // after some time ... .then(function(result) { // fulfilled, result is "hello" })
// after a while ...
promise .then(function(result) { // fulfilled, result still "hello" })
![Page 80: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/80.jpg)
Thenable are chainable
promise .then(function() { /* do something */ }) .then(function() { /* do something */ }) .then(function() { /* do something */ }) .then(function() { /* do something */ })
![Page 81: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/81.jpg)
Sequential composition
promise .then(refuel) .then(startEngine) .then(takeOff) .then(land)
![Page 82: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/82.jpg)
Pyramid demolished
promise .then(refuel) .then(startEngine) .then(takeOff) .then(land)
![Page 83: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/83.jpg)
Promisify
function after(time) { return new Promise(function(resolve) { setTimeout(resolve, time) })}
after(5000) .then(function() { // five seconds gone! })
![Page 84: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/84.jpg)
Promise propagation
promise .then(function() { /* called immediately */ }) .then(function() { /* called immediately */ })
![Page 85: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/85.jpg)
Promise propagation
promise .then(function() { return after(5000) })
// returns a promise .then(function() { /* called after 5 secs */ }) .then(function() { /* called after 5 secs */ })
![Page 86: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/86.jpg)
Promise propagation
promise .then(function() { return 5 })
// returns a value .then(function(result) { /* result == 5 */ })
![Page 87: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/87.jpg)
Promise propagationpromise .then(after(5000)) .then(function() { throw new Error("argh") })
// throws an error .then(function() { /* never called */ }) .then(null, function(err) {
// err == Error(“argh”)})
![Page 88: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/88.jpg)
Lovely error handling
promise .then(refuel) .then(startEngine) .then(takeOff) .then(land) .catch(function(err) { // deal with err })
![Page 89: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/89.jpg)
More compositionvar one = after(1000).then(function() { return 1 })var two = after(2000).then(function() { return 2 })
// parallel, wait for allPromise.all([one, two]).then(function(result) { // after 2 seconds // result == [1, 2]})
// parallel, wins the firstPromise.race([one, two]).then(function(result) { // after 1 second // result == 1})
![Page 90: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/90.jpg)
Stateful joy
![Page 91: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/91.jpg)
Promises have limited vision
![Page 92: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/92.jpg)
Promises have limited vision
setInterval(function() { // does success/error make sense? // what about next intervals ??}, 1000)
![Page 93: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/93.jpg)
Promises have limited vision
$button.on("click", function() { // does success/error make sense? // what about next events ??})
![Page 94: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/94.jpg)
Streams are weird beasts to promises
![Page 95: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/95.jpg)
Reactive programming
https://github.com/Reactive-Extensions/RxJS
![Page 96: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/96.jpg)
Eric Meijer
Reactive programming
![Page 97: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/97.jpg)
Observables are collections over time
![Page 98: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/98.jpg)
Iterators are pull
iterator.next() // => valueiterator.next() // => valueiterator.next() // => value
// it can return an erroriterator.next() // => Error("argh")
// it can enditerator.hasNext() // => falseiterator.next() // => null
![Page 99: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/99.jpg)
observable.subscribe( function(value) { // next value }, function(err) { // failure }, function() { // completed })
Observables are push
![Page 100: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/100.jpg)
Observables can dosetInterval
interval(1000).subscribe( function(value) { // value == undefined // value == undefined // ... }, function(err) { // never called }, function() { // when the interval is cleared })
![Page 101: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/101.jpg)
Observables can doevents
click("#button").subscribe( function(value) { // value == { x: 458, y: 788 } // value == { x: 492, y: 971 } // ... }, function(err) { // never called }, function() { // when click is unsubscribed })
![Page 102: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/102.jpg)
Observables can doasync calls
download(url).subscribe( function(image) { // once! // image == Image object }, function(err) { // once! // if error }, function() { // once! // when either succeeded or failed }
![Page 103: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/103.jpg)
Observables areall-around
![Page 104: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/104.jpg)
OOP structurefunctional compositionvar mouseup = Rx.Observable.fromEvent(dragTarget, 'mouseup')var mousemove = Rx.Observable.fromEvent(document, 'mousemove')var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown')
var mousedrag = mousedown.selectMany(function (md) {
// calculate offsets when mouse down var startX = md.offsetX, startY = md.offsetY
// Calculate delta with mousemove until mouseup return mousemove.select(function (mm) { return { left: mm.clientX - startX, top: mm.clientY - startY } }).takeUntil(mouseup)})
// Update positionvar subscription = mousedrag.subscribe(function (pos) { dragTarget.style.top = pos.top + 'px' dragTarget.style.left = pos.left + 'px'})
![Page 105: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/105.jpg)
Powerful model
![Page 106: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/106.jpg)
Used at scale byNetflix
https://github.com/Netflix/RxJava/wiki
![Page 107: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/107.jpg)
Take Away
![Page 108: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/108.jpg)
Blockif you can
![Page 109: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/109.jpg)
Choose the concurrencymodel that
fits you
![Page 110: The Strange World of Javascript and all its little Asynchronous Beasts](https://reader036.vdocuments.us/reader036/viewer/2022062702/554a0e44b4c90507558b4a30/html5/thumbnails/110.jpg)
@federicogalassi