64
Globalcode – Open4education JavaScript Promises Derek Stavis Engenheiro de Software

TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Embed Size (px)

Citation preview

Page 1: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

JavaScript PromisesDerek Stavis

Engenheiro de Software

Page 2: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Who?

Derek Stavis

github.com/derekstavis

Software Engineer

Ruby, JavaScript, Python, C

Node, React & Webpack Advocate

Page 3: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

How have you been doing asynchronous JavaScript?

Page 4: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

How have you been doing continuation passing?

Page 5: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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 });

Page 6: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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 })

Page 7: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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) { })

Page 8: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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) }) })

Page 9: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Node.js callback hell

Page 10: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

How could we flatten that tree?

Page 11: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

new Promise()

Page 12: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Formal definition

"A promise represents the eventual result of an asynchronous

operation."

Page 13: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Formal definition

"A promise represents the eventual result of an asynchronous

operation."

Page 14: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Enter Promises

An object which represents and manage the lifecycle of a future

result

Page 15: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise states

Pending

Fulfilled Rejected

Page 16: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise states

Promises aren't reusable

Page 17: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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' })

})

Page 18: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise API

var promise = new Promise(...)

promise.then(function (result) { console.log(result) })

=> { my: "data" }

Page 19: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise API

var promise = new Promise(...)

promise.catch(function (error) { console.log(error.message) })

=> A meaningful error

Page 20: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise API

Node.js callbacks can be easily wrapped in promises

Page 21: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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) } }) }

Page 22: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise API

Every .then and .catch return a new promise, so promises are

chainable

Page 23: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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)

Page 24: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Flattening the tree

Chaining allows flattening the callback hell and make continuation

passing look sequential

Page 25: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Flattening the tree

const fetchTuples = () => Promise.resolve([ [1, 1], [2, 2], [6, 4] ])

Page 26: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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))

Page 27: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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 }

Page 28: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise Implementation

Promise is a specification

Page 29: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise Implementation

There are a handful of Promise implementations

Page 30: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise Implementation

Solving different issues, focusing on different areas

Page 31: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promise Implementation

So I have to be tied to a single implementation?

Page 32: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

NOT HERE

Page 33: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promises/A+ Contract

https://promisesaplus.com

Page 34: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promises/A+ Contract

Promises/A+ provides interface and behaviour specification for

interoperable promises

Page 35: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promises/A+ Contract

So you are free to use the implementation which better fit

your needs while keeping your code compatible

Page 36: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Promises/A+ Contract

This contract was created because there was no native Promise specification in ECMAScript

Page 37: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

ECMAScript 2015 Promise

Since ECMAScript 2015 the Promise object was included in the spec

https://tc39.github.io/ecma262/#sec-promise-constructor

Page 38: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

ECMAScript 2015 Promise

It allows more fun stuff do be done

Page 39: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

ECMAScript 2015 Promise

Waiting for multiple Promises

Page 40: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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') })

Page 41: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

ECMAScript 2015 Promise

Racing multiple Promises

Page 42: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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') })

Page 43: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

You should definitely look into Promises

Page 44: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Because there's even more!

Page 45: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird A complete Promise library

http://bluebirdjs.com

Page 46: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird Promise

Catch rejections like exceptions

Page 47: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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

Page 48: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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)

Page 49: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird Promise

Spread Promise.all result as parameters

Page 50: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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') )

Page 51: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird Promise

Use .all & .spread for dynamic amount of promises

When doing fixed number of promises use .join

Page 52: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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') )

Page 53: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird Promise

Resolve objects with promises

Page 54: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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') )

Page 55: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Bluebird Promise

Do some .reduce with promises

Page 56: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Reduce promises results

const urls = fetchProjects()

Promise.reduce(urls, (total, url) => fetch(url).then(data => total + data.stars), 0)

Page 57: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

HTML Fetch A Promise approach to HTTP requests

https://fetch.spec.whatwg.org

Page 58: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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) })

Page 59: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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) })

Page 60: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

#DeprecateXHR

fetch is growing so powerful

Page 61: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

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"}

Page 62: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

#DeprecateXHR

fetch promise resolve as soon as headers are ready

Page 63: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Demo Fetching stuff from Github

https://github.com/derekstavis/promises-on-the-browser

Page 64: TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática

Globalcode – Open4education

Thanks for watching Questions?

github.com/derekstavis

twitter.com/derekstavis

facebook.com/derekstavis