KEMBAR78
JavaScript Promises | PDF
Globalcode – Open4education
JavaScript Promises
Derek Stavis
Engenheiro de Software
Globalcode – Open4education
Who?
Derek Stavis
github.com/derekstavis
Software Engineer
Ruby, JavaScript, Python, C
Node, React & Webpack Advocate
Globalcode – Open4education
How have you been doing
asynchronous JavaScript?
Globalcode – Open4education
How have you been doing
continuation passing?
Globalcode – Open4education
Using callback functions
// In the browser
setTimeout(function () {
// Will be called in the future
}, 2000);
// In the server
fs.readFile('file.txt', function () {
// Will be called when file.txt is read
});
Globalcode – Open4education
Node.js callback standard
fs.readFile('file.txt', function (err, data) {
// If an error occurred, err will have a value
// Always check for errors using if clauses
})
Globalcode – Open4education
Node.js callback scenario
Let’s say we have a fetch function
It does plain HTTP GET
Accepts a URL and a callback
Callback receives error and response
fetch ('url', function (err, res) { })
Globalcode – Open4education
Node.js callback scenario
fetch('/users/session', function (sessionError, user) {
if (sessionError) {
alert('Error fetching session')
return
}
fetch('/users/' + user.id + '/posts', function
(userErr, posts) {
if (userErr) {
alert('Error fetching user posts')
return
}
renderUserPosts(posts)
})
})
Globalcode – Open4education
Node.js callback hell
Globalcode – Open4education
How could we flatten that tree?
Globalcode – Open4education
new Promise()
Globalcode – Open4education
Formal definition
"A promise represents the eventual
result of an asynchronous
operation."
Globalcode – Open4education
Formal definition
"A promise represents the eventual
result of an asynchronous
operation."
Globalcode – Open4education
Enter Promises
An object which represents and
manage the lifecycle of a future
result
Globalcode – Open4education
Promise states
Pending
Fulfilled Rejected
Globalcode – Open4education
Promise states
Promises aren't reusable
Globalcode – Open4education
Promise API
// New Promises start in "Pending" state
new Promise(function (resolve, reject) {
// Transition to "Rejected" state
reject(new Error('A meaningful error'))
// Transition to "Fulfilled" state
resolve({ my: 'data' })
})
Globalcode – Open4education
Promise API
var promise = new Promise(...)
promise.then(function (result) {
console.log(result)
})
=> { my: "data" }
Globalcode – Open4education
Promise API
var promise = new Promise(...)
promise.catch(function (error) {
console.log(error.message)
})
=> A meaningful error
Globalcode – Open4education
Promise API
Node.js callbacks can be easily
wrapped in promises
Globalcode – Open4education
Promise API
function fetch (url) {
return new Promise(function (resolve, reject) {
request(url, function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
}
Globalcode – Open4education
Promise API
Every .then and .catch return a
new promise, so promises are
chainable
Globalcode – Open4education
Flattening the tree
function fetchPosts (user) {
return fetch('/users/' + user.id + '/posts')
}
function fetchSession () {
return fetch('/users/session')
}
fetchSession()
.catch(handleSessionError)
.then(fetchPosts)
.catch(handlePostsError)
.then(renderUserPosts)
Globalcode – Open4education
Flattening the tree
Chaining allows flattening the
callback hell and make continuation
passing look sequential
Globalcode – Open4education
Flattening the tree
const fetchTuples = () =>
Promise.resolve([
[1, 1],
[2, 2],
[6, 4]
])
Globalcode – Open4education
Chaining (a.k.a. sequence monad)
const makeObject = e => ({ l: e[0], r: e[1] })
const attachPlus = e => merge(e, { plus: e.l + e.r })
const attachMinus = e => merge(e, { minus: e.l - e.r })
const attachTimes = e => merge(e, { times: e.l * e.r })
const attachDivide = e => merge(e, { divide: e.l / e.r })
fetchTuples()
.then(map(makeObject))
.then(map(attachPlus))
.then(map(attachMinus))
.then(map(attachTimes))
.then(map(attachDivide))
.then(console.log.bind(console))
Globalcode – Open4education
Chaining (a.k.a. sequence monad)
{ l: 1, r: 1, plus: 2, minus: 0, times: 1, divide: 1 }
{ l: 2, r: 2, plus: 4, minus: 0, times: 4, divide: 1 }
{ l: 6, r: 4, plus: 10, minus: 2, times: 24, divide: 1.5 }
Globalcode – Open4education
Promise Implementation
Promise is a specification
Globalcode – Open4education
Promise Implementation
There are a handful of Promise
implementations
Globalcode – Open4education
Promise Implementation
Solving different issues, focusing
on different areas
Globalcode – Open4education
Promise Implementation
So I have to be tied to a single
implementation?
Globalcode – Open4education
NOT HERE
Globalcode – Open4education
Promises/A+ Contract
https://promisesaplus.com
Globalcode – Open4education
Promises/A+ Contract
Promises/A+ provides interface and
behaviour specification for
interoperable promises
Globalcode – Open4education
Promises/A+ Contract
So you are free to use the
implementation which better fit
your needs while keeping your code
compatible
Globalcode – Open4education
Promises/A+ Contract
This contract was created because
there was no native Promise
specification in ECMAScript
Globalcode – Open4education
ECMAScript 2015 Promise
Since ECMAScript 2015 the Promise
object was included in the spec
https://tc39.github.io/ecma262/#sec-promise-
constructor
Globalcode – Open4education
ECMAScript 2015 Promise
It allows more fun stuff do be done
Globalcode – Open4education
ECMAScript 2015 Promise
Waiting for multiple Promises
Globalcode – Open4education
Waiting for multiple Promises
var promises = [
new Promise(function (resolve, reject) {
setTimeout(resolve, 1000);
}),
new Promise(function (resolve, reject) {
setTimeout(resolve, 2000);
})
]
Promise.all(promises).then(function () {
console.log('Ran after 2 seconds')
})
Globalcode – Open4education
ECMAScript 2015 Promise
Racing multiple Promises
Globalcode – Open4education
Racing multiple Promises
var promises = [
new Promise(function (resolve, reject) {
setTimeout(resolve, 1000);
}),
new Promise(function (resolve, reject) {
setTimeout(resolve, 2000);
})
]
Promise.race(promises).then(function () {
console.log('Ran after 1 second')
})
Globalcode – Open4education
You should definitely look into
Promises
Globalcode – Open4education
Because there's even more!
Globalcode – Open4education
Bluebird
A complete Promise library
http://bluebirdjs.com
Globalcode – Open4education
Bluebird Promise
Catch rejections like exceptions
Globalcode – Open4education
Fine-grained exceptions
function SessionError(message) {
this.message = message
this.name = "SessionError"
Error.captureStackTrace(this, SessionError)
}
SessionError.prototype =
Object.create(Error.prototype)
SessionError.prototype.constructor = SessionError
Globalcode – Open4education
Fine-grained exceptions
function fetchPosts (user) {
throw new PostsError('could not fetch posts')
}
function fetchSession () {
return new SessionError('could not fetch session')
}
fetchSession()
.then(fetchPosts)
.then(renderPosts)
.catch(SessionError, handleSessionError)
.catch(PostsError, handlePostsError)
Globalcode – Open4education
Bluebird Promise
Spread Promise.all result as
parameters
Globalcode – Open4education
Parameter spread
Promise.all([
download('http://foo.bar/file.tar.gz'),
download('http://foo.bar/file.tar.gz.sig')
]).spread((file, signature) =>
sign(file) == signature
? Promise.resolve(file)
: Promise.reject('invalid signature')
)
Globalcode – Open4education
Bluebird Promise
Use .all & .spread for dynamic
amount of promises
When doing fixed number of
promises use .join
Globalcode – Open4education
Join promises results
Promise.join(
download('http://foo.bar/file.tar.gz'),
download('http://foo.bar/file.tar.gz.sig'),
(file, signature) =>
sign(file) == signature
? Promise.resolve(file)
: Promise.reject('invalid signature')
)
Globalcode – Open4education
Bluebird Promise
Resolve objects with promises
Globalcode – Open4education
Join promises results
Promise.props({
file: download('http://foo.bar/file.tar.gz'),
sig: download('http://foo.bar/file.tar.gz.sig')
}).then(data =>
sign(data.file) == data.sig
? Promise.resolve(file)
: Promise.reject('invalid signature')
)
Globalcode – Open4education
Bluebird Promise
Do some .reduce with promises
Globalcode – Open4education
Reduce promises results
const urls = fetchProjects()
Promise.reduce(urls, (total, url) =>
fetch(url).then(data =>
total + data.stars), 0)
Globalcode – Open4education
HTML Fetch
A Promise approach to HTTP requests
https://fetch.spec.whatwg.org
Globalcode – Open4education
#DeprecateXHR
fetch('/users.json')
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
Globalcode – Open4education
#DeprecateXHR
fetch('/users.json')
.then(function(response) {
return response.json()
fetch('/users.json')
.then(function(response) {
return response.json()
}).then(function(json) {
console.log('parsed json', json)
}).catch(function(ex) {
console.log('parsing failed', ex)
})
Globalcode – Open4education
#DeprecateXHR
fetch is growing so powerful
Globalcode – Open4education
#DeprecateXHR
$ telnet mockbin.org 80
GET /bin/2294df68-ae10-4336-a732-3170597543a9 HTTP/1.1
Accept: */*
Host: mockbin.org
HTTP/1.1 200 OK
Content-Type: text/html
Custom-Header: CustomValue
{"fetch": "is so cool"}
Globalcode – Open4education
#DeprecateXHR
fetch promise resolve as soon as
headers are ready
Globalcode – Open4education
Demo
Fetching stuff from Github
https://github.com/derekstavis/
promises-on-the-browser
Globalcode – Open4education
Thanks for watching
Questions?
github.com/derekstavis
twitter.com/derekstavis
facebook.com/derekstavis

JavaScript Promises