SlideShare uma empresa Scribd logo
1 de 33
Baixar para ler offline
Promises
Asynchronous Control Flow
A long time ago in a galaxy far far away...
The problem
Q: How to control the asynchronous flow of your
application when there are dependencies between
two steps?
A: I can use Callbacks :)
function asyncFunction1(function (err, result) {
// do something here...
asyncFuncion2(function (err2, result2) {
// other stuff here...
})
})
However… Callbacks can get ugly
module.exports.verifyPassword = function(user, password, done) {
if(typeof password !== ‘string’) {
done(new Error(‘password should be a string’))
}
computeHash(password, user.passwordHashOpts, function(err, hash) {
if(err) {
done(err)
}
done(null, hash === user.passwordHash)
})
}
Callback being called multiple times
This one is easily fixed though...
module.exports.verifyPassword = function(user, password, done) {
if(typeof password !== ‘string’) {
return done(new Error(‘password should be a string’))
}
computeHash(password, user.passwordHashOpts, function(err, hash) {
if(err) {
return done(err)
}
return done(null, hash === user.passwordHash)
})
}
Always return when calling the callback
Q: How execute asynchronous function in
parallel and proceed when all have finished?
But what about parallel execution?
var finished = [false, false]
function asyncFunction1(function (err, result) {
// do some stuff
finished[0] = true
if (finished[0] === true && finished[1] === true) {
// proceed…
}
})
function asyncFunction2(function (err, result) {
// do some other stuff
finished[1] = true
if (finished[0] === true && finished[1] === true) {
// proceed…
}
})
The callback hell
Find a better way you must...
The good ol’ async¹ module
async.waterfall([
function(callback) {
callback(null, 'one', 'two');
},
function(arg1, arg2, callback) {
// arg1 = 'one' and arg2 = 'two'
callback(null, 'three');
},
function(arg1, callback) {
// arg1 = 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
async.parallel([
function(callback){
setTimeout(function(){
callback(null, 'one');
}, 200);
},
function(callback){
setTimeout(function(){
callback(null, 'two');
}, 100);
}
],
// optional callback
function(err, results){
// the results array will equal ['one','two']
even though
// the second function had a shorter timeout.
});
¹ https://github.com/caolan/async
But it can get cumbersome too...
What if I need to pass an argument to the first
function in the waterfall?
async.waterfall([
async.apply(myFirstFunction, 'zero'),
mySecondFunction,
myLastFunction,
], function (err, result) {
// result = 'done'
});
function myFirstFunction(arg1, callback) {
// arg1 now equals 'zero'
callback(null, 'one', 'two');
}
function mySecondFunction(arg1, arg2, callback) {
// arg1 = 'one' and arg2 = 'two'
callback(null, 'three');
}
function myLastFunction(arg1, callback) {
// arg1 = 'three'
callback(null, 'done');
}
DRY*
Error handling can be tiresome…
You have to bubble your errors up in every layer of
code you have.
And if you forget doing so, a wild bug may appear...
* Don’t Repeat Yourserlf
async.waterfall([
function(callback) {
doSomething(function(err, result){
if (err) return callback(err)
callback(null, result, 'another-thing');
})
},
function(arg1, arg2, callback) {
doAnotherStuff(function(err, result){
if (err) return callback(err)
callback(null, result);
})
},
function(arg1, callback) {
doAnotherStuff(function(err, result){
if (err) return callback(err)
callback(null, result);
})
}
], function (err, result) {
// result now equals 'done'
});
Bug used “confusion”.
It was very effective.
Promises F.T.W.
What is a promise?
The core idea behind promises is that it represents the result of an asynchronous
operation. A promise is in one of three different states:
- Pending: The initial state of a promise.
- Fulfilled: The state of a promise representing a successful operation.
- Rejected: The state of a promise representing a failed operation.
How does a promise work?
The State Diagram of a promise is as simple as this one:
Clarifying a little bit
- When pending, a promise:
○ may transition to either the fulfilled or rejected state.
- When fulfilled, a promise:
○ must not transition to any other state.
○ must have a value, which must not change.
- When rejected, a promise:
○ must not transition to any other state.
○ must have a reason, which must not change.
The “then” method
The “then” method is called when a promise is
either fulfilled or rejected.
This two conditions are treated by different
callbacks:
promise.then(onFulfilled, onRejected)
- onFulfilled(value): value of fulfilment of the
promise as its first argument
- onRejected(reason): reason of rejection of
the promise as its first argument. This
argument is optional.
functionReturningPromise.then(function(value){
// do something with value
}, function (reason) {
// do something if failed
})
Promise chaining
The “then” method always returns a new promise,
so it can be chained.
Even if your callbacks return a value, the promise
implementation will wrap it into a brand new
promise before returning it.
functionReturningPromise.then(function(value){
return 10
})
.then(function (number) {
console.log(number) // 10
})
.then(...)
.then(...)
.then(...)
.then(...)
.then(...)
// The chaining can go indefinetly
Error handling
If any error is thrown within a then callback, a
rejected promise will be automatically returned
with the error as its reason.
The immediately after then call will only execute
the onRejected callback.
If onRejected is not provided or is not a function,
the error will be passed to the next chained then.
If no then call in the chain have a onRejected
callback, the error will be thrown to the main code.
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.then(function (someArg) {
// do nothing
}, function (reason) {
console.log(reason) // Error: Something …
return 42 // Will return a resolved promise
})
Error bubbling
If onRejected is not provided or is not a function,
the error will be passed to the next chained then.
If the next chained then has the onRejected
callback, it will be called, giving you a possibility of
dealing with the error.
IMPORTANT: if you don’t throw a new error or
re-throw the error argument, the then method will
return a promise that is resolved with the return
value of the onRejected callback.
If no then call in the chain have a onRejected
callback, the error will be thrown to the main code.
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.then(function (number) {
console.log(number) // Will be bypassed
})
.then(function (someArg) {
// do nothing
}, function (reason) {
console.log(reason) // Error: Something …
// Will return a resolved promise
})
.then(function (number) {
console.log(number)
// undefined because the previous
// callback doesn’t return a value
})
Error catching
In most situations, you only want to deal with
possible errors once.
You can do this by adding a then call at the end of
your chain with only the onRejected callback.
This way, any subsequent then call after the error
throwing will be bypassed and the error will only
be handled by the last one.
Since the last then call is only for error catching,
you don’t need to set a onResolved callback and may
use null instead.
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.then(function (...) {
// Will be bypassed
})
.then(function (...) {
// Will be bypassed
})
.then(function (...) {
// Will be bypassed
})
.then(null, function (error) {
// Error: Something …
console.log(error)
})
Promises A+
Standardization
Promise A+¹ is a standard specification for promise
implementations.
It allows interoperability between different
promise libraries.
You don’t need to worry about what
implementation of promise a 3rd party module
uses, you can seamlessly integrate it into your code,
as long as it respects the A+ specs.
The specs are at the same time powerful and dead
simple: less than 100 lines of text in plain English.
¹ https://promisesaplus.com/
someLibrary.methodReturningPromise()
.then(function (result) {
return anotherLibrary.anotherPromise()
})
.then(function (anotherResult) {
// ...
})
I mean, a de facto standard...
Promises are now part of the core¹ of EcmaScript 6
(ES6).
That means it is available as part of the standard
library of modern Javascript engines:
● Node.js >= v0.12.*
● Any modern and updated browser (Firefox,
Chrome, Safari, Edge, etc. -- NOT IE)
¹ https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
² http://caniuse.com/#feat=promises
²
Enhancing Promises
Parallel execution
Most of the promise implementations (including
the core one in ES6) have some extra methods will
allow you to have asynchronous code running in
parallel.
The Promise.all¹ method will take an array of
promises as an argument and will return a promise
that will only be resolved when and if all the input
promises are resolved.
The Promise.race¹ method will also take an array of
promises, but will return a promise that resolves to
the value of the first of the input to be resolved.
Promise.all([promise1, promise2, promise3])
.then(function (result) {
// result will be an array with the values
// of the input promises.
// The order is preserved, so you’ll have:
// [resPromise1, resPromise2, resPromise3]
})
Promise.race([promise1, promise2, promise3])
.then(function (result) {
// result will be the either resPromise1,
// resPromise2 or resPromise3, depending
// on which promise finishes firt
})
¹ Not part of the Promise A+ specification
The catch method
The catch¹ method is just a syntactic sugar around
the last-then-treats-error pattern discussed before.
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.then(null, function (error) {
console.log(error)
})
// Can be rewritten as following in most
// implementations of Promise:
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.catch(function (error) {
console.log(error)
})
¹ Not part of the Promise A+ specification
Creating settled promises
Another syntactic sugar allows you to create
promises that are already fulfilled or rejected,
through the helper methods Promise.resolve and
Promise.reject.
This can be very useful in cases that your interface
states you should return a promise, but you already
have the value to return (ex.: caching).
var cache = {}
functionReturningPromise.then(function(value){
throw new Error(‘Something bad happened’)
})
.then(function (result) {
if (cache[result] !== undefined) {
return Promise.resolve(cache[result])
} else {
return getFreshData(result)
.then(function (data) {
cache[result] = data
return data
)}
}
})
¹ This is not part of the Promise A+ specification
Non-standard¹ cool extras
The finally method allows you to have a callback
that will be executed either if the promise chain is
resolved or rejected.
The tap method is a really useful syntactic sugar
that allows you to intercept the result of a promise,
but automatically passing it down the chain.
The props method is like Promise.all, but resolves
to an object instead of an array.
db.connect() // Implemented using bluebird
.then(function() {
// run some queries
})
.finally(function () {
// no matter what, close the connection
db.disconnect()
})
var Promise = require('bluebird')
Promise.resolve(42)
// will print 42 into the console and return it
.tap(console.log.bind(console))
.then(function (result) {
// result is still 42
})
Promise.props({ a: getA(), b : getB()})
.then(function (obj) {
// Will print { a : …, b : … }
console.log(obj)
})
¹ Based on Bluebird (http://bluebirdjs.com/docs/) -- a full-featured promise implementation
Promisify all the things!
Converting callback-based code
Bluebird¹ has some utility methods that will adapt
callback-based functions and libs to use promises.
The Promise.promisify method will take any
error-first callback and return a promise that will
be resolved if the callback is called without error or
rejected otherwise.
The Promise.promisifyAll method will take an
objects and iterate over all it’s methods and create
a new implementation of them, keeping the same
name, suffixed by “Async”.
Var Promise = require('bluebird’)
var fs = require('fs')
var readFileAsync = Promise.promisify(fs.readFile)
readFileAsync('someFile.ext')
.then(function (contents) {
// do something
})
// or...
Promise.promisifyAll(fs)
fs.readFileAsync('someFile.ext')
.then(function (contents) {
// do something
})
¹ http://bluebirdjs.com/
A-a-any d-d-doubts?
@hjpbarcelos
henriquebarcelos
Henrique José Pires Barcelos
Fullstack Software Engineer @ Revmob
About the author

Mais conteúdo relacionado

Mais procurados

JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsColin DeCarlo
 
Getting Comfortable with JS Promises
Getting Comfortable with JS PromisesGetting Comfortable with JS Promises
Getting Comfortable with JS PromisesAsa Kusuma
 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best PraticesChengHui Weng
 
JavaScript promise
JavaScript promiseJavaScript promise
JavaScript promiseeslam_me
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...PVS-Studio
 
JavaScript Loop: Optimization of Weak Typing
JavaScript Loop: Optimization of Weak TypingJavaScript Loop: Optimization of Weak Typing
JavaScript Loop: Optimization of Weak TypingJanlay Wu
 
[C++]3 loop statement
[C++]3 loop statement[C++]3 loop statement
[C++]3 loop statementJunyoung Jung
 
A Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-StudioA Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-StudioAndrey Karpov
 
Introduction to Asynchronous scala
Introduction to Asynchronous scalaIntroduction to Asynchronous scala
Introduction to Asynchronous scalaStratio
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: FunctionsAdam Crabtree
 
Using Akka Futures
Using Akka FuturesUsing Akka Futures
Using Akka FuturesKnoldus Inc.
 
Pro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise ApplicationsPro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise ApplicationsStephen Chin
 
Ownership System in Rust
Ownership System in RustOwnership System in Rust
Ownership System in RustChih-Hsuan Kuo
 
Code generation with javac plugin
Code generation with javac pluginCode generation with javac plugin
Code generation with javac pluginOleksandr Radchykov
 

Mais procurados (20)

JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
Getting Comfortable with JS Promises
Getting Comfortable with JS PromisesGetting Comfortable with JS Promises
Getting Comfortable with JS Promises
 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best Pratices
 
JavaScript promise
JavaScript promiseJavaScript promise
JavaScript promise
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
 
JavaScript Loop: Optimization of Weak Typing
JavaScript Loop: Optimization of Weak TypingJavaScript Loop: Optimization of Weak Typing
JavaScript Loop: Optimization of Weak Typing
 
Control structures
Control structuresControl structures
Control structures
 
[C++]3 loop statement
[C++]3 loop statement[C++]3 loop statement
[C++]3 loop statement
 
A Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-StudioA Spin-off: Firebird Checked by PVS-Studio
A Spin-off: Firebird Checked by PVS-Studio
 
Introduction to Asynchronous scala
Introduction to Asynchronous scalaIntroduction to Asynchronous scala
Introduction to Asynchronous scala
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
 
Completable future
Completable futureCompletable future
Completable future
 
Using Akka Futures
Using Akka FuturesUsing Akka Futures
Using Akka Futures
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Cocoa heads 09112017
Cocoa heads 09112017Cocoa heads 09112017
Cocoa heads 09112017
 
Pro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise ApplicationsPro Java Fx – Developing Enterprise Applications
Pro Java Fx – Developing Enterprise Applications
 
Exporter Proxy
Exporter ProxyExporter Proxy
Exporter Proxy
 
Ownership System in Rust
Ownership System in RustOwnership System in Rust
Ownership System in Rust
 
C# Asynchronous delegates
C# Asynchronous delegatesC# Asynchronous delegates
C# Asynchronous delegates
 
Code generation with javac plugin
Code generation with javac pluginCode generation with javac plugin
Code generation with javac plugin
 

Destaque

Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...
Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...
Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...gumenuk111
 
презентація досвіду роботи
презентація досвіду роботипрезентація досвіду роботи
презентація досвіду роботиІрина Гаврилюк
 
44030397 model-pembelajaran-ctl
44030397 model-pembelajaran-ctl44030397 model-pembelajaran-ctl
44030397 model-pembelajaran-ctlMerviany
 
Topiki istoria-Βιωματικές Δράσεις Γ΄ Γυμνασίου
Topiki istoria-Βιωματικές Δράσεις Γ΄ ΓυμνασίουTopiki istoria-Βιωματικές Δράσεις Γ΄ Γυμνασίου
Topiki istoria-Βιωματικές Δράσεις Γ΄ ΓυμνασίουKiki Sakka
 
Mueble multifuncional
Mueble multifuncionalMueble multifuncional
Mueble multifuncionalcarlaparadas
 
Elmer figueroa arce alias chayanne presentacion
Elmer figueroa arce alias chayanne presentacionElmer figueroa arce alias chayanne presentacion
Elmer figueroa arce alias chayanne presentacionpaolatezanos
 

Destaque (19)

Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...
Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...
Уроки "Основи здров’я" у 3 класі Брагинівської ЗОШ І-ІІІ ступенів класовод Па...
 
Collaborative platformin the agricultural sectorin Algeria. Towards a Knowled...
Collaborative platformin the agricultural sectorin Algeria. Towards a Knowled...Collaborative platformin the agricultural sectorin Algeria. Towards a Knowled...
Collaborative platformin the agricultural sectorin Algeria. Towards a Knowled...
 
презентація досвіду роботи
презентація досвіду роботипрезентація досвіду роботи
презентація досвіду роботи
 
44030397 model-pembelajaran-ctl
44030397 model-pembelajaran-ctl44030397 model-pembelajaran-ctl
44030397 model-pembelajaran-ctl
 
Power point
Power pointPower point
Power point
 
Lat uts bahasa xi
Lat uts bahasa xiLat uts bahasa xi
Lat uts bahasa xi
 
Topiki istoria-Βιωματικές Δράσεις Γ΄ Γυμνασίου
Topiki istoria-Βιωματικές Δράσεις Γ΄ ΓυμνασίουTopiki istoria-Βιωματικές Δράσεις Γ΄ Γυμνασίου
Topiki istoria-Βιωματικές Δράσεις Γ΄ Γυμνασίου
 
Πολυμέρης - Βιωματικές Δράσεις και ΤΠΕ
Πολυμέρης - Βιωματικές Δράσεις και ΤΠΕΠολυμέρης - Βιωματικές Δράσεις και ΤΠΕ
Πολυμέρης - Βιωματικές Δράσεις και ΤΠΕ
 
Ppt ctl dan paikem
Ppt ctl dan paikemPpt ctl dan paikem
Ppt ctl dan paikem
 
How To Use Google Calendar
How To Use Google CalendarHow To Use Google Calendar
How To Use Google Calendar
 
Humidification
HumidificationHumidification
Humidification
 
Trono dr facilier
Trono dr facilierTrono dr facilier
Trono dr facilier
 
MADESOL | MADERAS
MADESOL | MADERAS MADESOL | MADERAS
MADESOL | MADERAS
 
Diseño de Ottoman : MAHI
Diseño de Ottoman : MAHI Diseño de Ottoman : MAHI
Diseño de Ottoman : MAHI
 
Mueble multifuncional
Mueble multifuncionalMueble multifuncional
Mueble multifuncional
 
Mueble multifuncional
Mueble multifuncionalMueble multifuncional
Mueble multifuncional
 
Mueble multifuncional
Mueble multifuncionalMueble multifuncional
Mueble multifuncional
 
Ottoman RGDM-03
Ottoman  RGDM-03Ottoman  RGDM-03
Ottoman RGDM-03
 
Elmer figueroa arce alias chayanne presentacion
Elmer figueroa arce alias chayanne presentacionElmer figueroa arce alias chayanne presentacion
Elmer figueroa arce alias chayanne presentacion
 

Semelhante a Asynchronous Control Flow with Promises

Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsPiotr Pelczar
 
Asynchronous development in JavaScript
Asynchronous development  in JavaScriptAsynchronous development  in JavaScript
Asynchronous development in JavaScriptAmitai Barnea
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAnkit Agarwal
 
Angular promises and http
Angular promises and httpAngular promises and http
Angular promises and httpAlexe Bogdan
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Codemotion
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)Domenic Denicola
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesHùng Nguyễn Huy
 
AngularJS, More Than Directives !
AngularJS, More Than Directives !AngularJS, More Than Directives !
AngularJS, More Than Directives !Gaurav Behere
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptjnewmanux
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the mastersAra Pehlivanian
 
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24Joachim Bengtsson
 
Async History - javascript
Async History - javascriptAsync History - javascript
Async History - javascriptNishchit Dhanani
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
JavaScript Interview Questions 2023
JavaScript Interview Questions 2023JavaScript Interview Questions 2023
JavaScript Interview Questions 2023Laurence Svekis ✔
 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bitsChris Saylor
 
Better react/redux apps using redux-saga
Better react/redux apps using redux-sagaBetter react/redux apps using redux-saga
Better react/redux apps using redux-sagaYounes (omar) Meliani
 

Semelhante a Asynchronous Control Flow with Promises (20)

Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Asynchronous development in JavaScript
Asynchronous development  in JavaScriptAsynchronous development  in JavaScript
Asynchronous development in JavaScript
 
Node js
Node jsNode js
Node js
 
Avoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promisesAvoiding callback hell in Node js using promises
Avoiding callback hell in Node js using promises
 
Promises & limbo
Promises & limboPromises & limbo
Promises & limbo
 
Angular promises and http
Angular promises and httpAngular promises and http
Angular promises and http
 
You promise?
You promise?You promise?
You promise?
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & Promises
 
AngularJS, More Than Directives !
AngularJS, More Than Directives !AngularJS, More Than Directives !
AngularJS, More Than Directives !
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the masters
 
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24
Nevyn — Promise, It's Async! Swift Language User Group Lightning Talk 2015-09-24
 
Async History - javascript
Async History - javascriptAsync History - javascript
Async History - javascript
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
JavaScript Interview Questions 2023
JavaScript Interview Questions 2023JavaScript Interview Questions 2023
JavaScript Interview Questions 2023
 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bits
 
Better react/redux apps using redux-saga
Better react/redux apps using redux-sagaBetter react/redux apps using redux-saga
Better react/redux apps using redux-saga
 
[2015/2016] JavaScript
[2015/2016] JavaScript[2015/2016] JavaScript
[2015/2016] JavaScript
 

Último

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 

Último (20)

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 

Asynchronous Control Flow with Promises

  • 2. A long time ago in a galaxy far far away...
  • 3. The problem Q: How to control the asynchronous flow of your application when there are dependencies between two steps? A: I can use Callbacks :) function asyncFunction1(function (err, result) { // do something here... asyncFuncion2(function (err2, result2) { // other stuff here... }) })
  • 4. However… Callbacks can get ugly module.exports.verifyPassword = function(user, password, done) { if(typeof password !== ‘string’) { done(new Error(‘password should be a string’)) } computeHash(password, user.passwordHashOpts, function(err, hash) { if(err) { done(err) } done(null, hash === user.passwordHash) }) } Callback being called multiple times
  • 5. This one is easily fixed though... module.exports.verifyPassword = function(user, password, done) { if(typeof password !== ‘string’) { return done(new Error(‘password should be a string’)) } computeHash(password, user.passwordHashOpts, function(err, hash) { if(err) { return done(err) } return done(null, hash === user.passwordHash) }) } Always return when calling the callback
  • 6. Q: How execute asynchronous function in parallel and proceed when all have finished? But what about parallel execution? var finished = [false, false] function asyncFunction1(function (err, result) { // do some stuff finished[0] = true if (finished[0] === true && finished[1] === true) { // proceed… } }) function asyncFunction2(function (err, result) { // do some other stuff finished[1] = true if (finished[0] === true && finished[1] === true) { // proceed… } })
  • 8. Find a better way you must...
  • 9. The good ol’ async¹ module async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 = 'one' and arg2 = 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 = 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' }); async.parallel([ function(callback){ setTimeout(function(){ callback(null, 'one'); }, 200); }, function(callback){ setTimeout(function(){ callback(null, 'two'); }, 100); } ], // optional callback function(err, results){ // the results array will equal ['one','two'] even though // the second function had a shorter timeout. }); ¹ https://github.com/caolan/async
  • 10. But it can get cumbersome too... What if I need to pass an argument to the first function in the waterfall? async.waterfall([ async.apply(myFirstFunction, 'zero'), mySecondFunction, myLastFunction, ], function (err, result) { // result = 'done' }); function myFirstFunction(arg1, callback) { // arg1 now equals 'zero' callback(null, 'one', 'two'); } function mySecondFunction(arg1, arg2, callback) { // arg1 = 'one' and arg2 = 'two' callback(null, 'three'); } function myLastFunction(arg1, callback) { // arg1 = 'three' callback(null, 'done'); }
  • 11. DRY* Error handling can be tiresome… You have to bubble your errors up in every layer of code you have. And if you forget doing so, a wild bug may appear... * Don’t Repeat Yourserlf async.waterfall([ function(callback) { doSomething(function(err, result){ if (err) return callback(err) callback(null, result, 'another-thing'); }) }, function(arg1, arg2, callback) { doAnotherStuff(function(err, result){ if (err) return callback(err) callback(null, result); }) }, function(arg1, callback) { doAnotherStuff(function(err, result){ if (err) return callback(err) callback(null, result); }) } ], function (err, result) { // result now equals 'done' }); Bug used “confusion”. It was very effective.
  • 13. What is a promise? The core idea behind promises is that it represents the result of an asynchronous operation. A promise is in one of three different states: - Pending: The initial state of a promise. - Fulfilled: The state of a promise representing a successful operation. - Rejected: The state of a promise representing a failed operation.
  • 14. How does a promise work? The State Diagram of a promise is as simple as this one:
  • 15. Clarifying a little bit - When pending, a promise: ○ may transition to either the fulfilled or rejected state. - When fulfilled, a promise: ○ must not transition to any other state. ○ must have a value, which must not change. - When rejected, a promise: ○ must not transition to any other state. ○ must have a reason, which must not change.
  • 16. The “then” method The “then” method is called when a promise is either fulfilled or rejected. This two conditions are treated by different callbacks: promise.then(onFulfilled, onRejected) - onFulfilled(value): value of fulfilment of the promise as its first argument - onRejected(reason): reason of rejection of the promise as its first argument. This argument is optional. functionReturningPromise.then(function(value){ // do something with value }, function (reason) { // do something if failed })
  • 17. Promise chaining The “then” method always returns a new promise, so it can be chained. Even if your callbacks return a value, the promise implementation will wrap it into a brand new promise before returning it. functionReturningPromise.then(function(value){ return 10 }) .then(function (number) { console.log(number) // 10 }) .then(...) .then(...) .then(...) .then(...) .then(...) // The chaining can go indefinetly
  • 18. Error handling If any error is thrown within a then callback, a rejected promise will be automatically returned with the error as its reason. The immediately after then call will only execute the onRejected callback. If onRejected is not provided or is not a function, the error will be passed to the next chained then. If no then call in the chain have a onRejected callback, the error will be thrown to the main code. functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .then(function (someArg) { // do nothing }, function (reason) { console.log(reason) // Error: Something … return 42 // Will return a resolved promise })
  • 19. Error bubbling If onRejected is not provided or is not a function, the error will be passed to the next chained then. If the next chained then has the onRejected callback, it will be called, giving you a possibility of dealing with the error. IMPORTANT: if you don’t throw a new error or re-throw the error argument, the then method will return a promise that is resolved with the return value of the onRejected callback. If no then call in the chain have a onRejected callback, the error will be thrown to the main code. functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .then(function (number) { console.log(number) // Will be bypassed }) .then(function (someArg) { // do nothing }, function (reason) { console.log(reason) // Error: Something … // Will return a resolved promise }) .then(function (number) { console.log(number) // undefined because the previous // callback doesn’t return a value })
  • 20. Error catching In most situations, you only want to deal with possible errors once. You can do this by adding a then call at the end of your chain with only the onRejected callback. This way, any subsequent then call after the error throwing will be bypassed and the error will only be handled by the last one. Since the last then call is only for error catching, you don’t need to set a onResolved callback and may use null instead. functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .then(function (...) { // Will be bypassed }) .then(function (...) { // Will be bypassed }) .then(function (...) { // Will be bypassed }) .then(null, function (error) { // Error: Something … console.log(error) })
  • 22. Standardization Promise A+¹ is a standard specification for promise implementations. It allows interoperability between different promise libraries. You don’t need to worry about what implementation of promise a 3rd party module uses, you can seamlessly integrate it into your code, as long as it respects the A+ specs. The specs are at the same time powerful and dead simple: less than 100 lines of text in plain English. ¹ https://promisesaplus.com/ someLibrary.methodReturningPromise() .then(function (result) { return anotherLibrary.anotherPromise() }) .then(function (anotherResult) { // ... })
  • 23. I mean, a de facto standard... Promises are now part of the core¹ of EcmaScript 6 (ES6). That means it is available as part of the standard library of modern Javascript engines: ● Node.js >= v0.12.* ● Any modern and updated browser (Firefox, Chrome, Safari, Edge, etc. -- NOT IE) ¹ https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise ² http://caniuse.com/#feat=promises ²
  • 25. Parallel execution Most of the promise implementations (including the core one in ES6) have some extra methods will allow you to have asynchronous code running in parallel. The Promise.all¹ method will take an array of promises as an argument and will return a promise that will only be resolved when and if all the input promises are resolved. The Promise.race¹ method will also take an array of promises, but will return a promise that resolves to the value of the first of the input to be resolved. Promise.all([promise1, promise2, promise3]) .then(function (result) { // result will be an array with the values // of the input promises. // The order is preserved, so you’ll have: // [resPromise1, resPromise2, resPromise3] }) Promise.race([promise1, promise2, promise3]) .then(function (result) { // result will be the either resPromise1, // resPromise2 or resPromise3, depending // on which promise finishes firt }) ¹ Not part of the Promise A+ specification
  • 26. The catch method The catch¹ method is just a syntactic sugar around the last-then-treats-error pattern discussed before. functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .then(null, function (error) { console.log(error) }) // Can be rewritten as following in most // implementations of Promise: functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .catch(function (error) { console.log(error) }) ¹ Not part of the Promise A+ specification
  • 27. Creating settled promises Another syntactic sugar allows you to create promises that are already fulfilled or rejected, through the helper methods Promise.resolve and Promise.reject. This can be very useful in cases that your interface states you should return a promise, but you already have the value to return (ex.: caching). var cache = {} functionReturningPromise.then(function(value){ throw new Error(‘Something bad happened’) }) .then(function (result) { if (cache[result] !== undefined) { return Promise.resolve(cache[result]) } else { return getFreshData(result) .then(function (data) { cache[result] = data return data )} } }) ¹ This is not part of the Promise A+ specification
  • 28. Non-standard¹ cool extras The finally method allows you to have a callback that will be executed either if the promise chain is resolved or rejected. The tap method is a really useful syntactic sugar that allows you to intercept the result of a promise, but automatically passing it down the chain. The props method is like Promise.all, but resolves to an object instead of an array. db.connect() // Implemented using bluebird .then(function() { // run some queries }) .finally(function () { // no matter what, close the connection db.disconnect() }) var Promise = require('bluebird') Promise.resolve(42) // will print 42 into the console and return it .tap(console.log.bind(console)) .then(function (result) { // result is still 42 }) Promise.props({ a: getA(), b : getB()}) .then(function (obj) { // Will print { a : …, b : … } console.log(obj) }) ¹ Based on Bluebird (http://bluebirdjs.com/docs/) -- a full-featured promise implementation
  • 29. Promisify all the things!
  • 30. Converting callback-based code Bluebird¹ has some utility methods that will adapt callback-based functions and libs to use promises. The Promise.promisify method will take any error-first callback and return a promise that will be resolved if the callback is called without error or rejected otherwise. The Promise.promisifyAll method will take an objects and iterate over all it’s methods and create a new implementation of them, keeping the same name, suffixed by “Async”. Var Promise = require('bluebird’) var fs = require('fs') var readFileAsync = Promise.promisify(fs.readFile) readFileAsync('someFile.ext') .then(function (contents) { // do something }) // or... Promise.promisifyAll(fs) fs.readFileAsync('someFile.ext') .then(function (contents) { // do something }) ¹ http://bluebirdjs.com/
  • 32.
  • 33. @hjpbarcelos henriquebarcelos Henrique José Pires Barcelos Fullstack Software Engineer @ Revmob About the author