Promises
IN THEORY AND REALITY
"OH GOD, KILL ME NOW"
Difficult to explain
What the fuck is a monad anyway?
Over-hyped
"PROMISES ARE THE FUTURE"
willyd - every day
Not the solution to
"Why stop at lists! Promises in a box! Promises with a fox! Attributes are promises! Arrays are promises! Everything is a promise!"
LIFE
Drew Crawford
- 2013
THE
UNIVERSE
AND
EVERYTHING
What Are promises?
promises/a+
- Have a then method which returns a promise
- Maintain state: 'pending', 'fulfilled', 'rejected'
- Must follow the promise resolution procedure
doSomething().then(doSomethingAfter);
PRomises can be resolved or rejected
function foo(bar){
try{
var result = bar.toLowerCase();
return Promise.resolve(result);
}
catch(error){
return Promise.reject(error);
}
}
var loadFoo = foo('THE FUTURE');
loadFoo.then(function(result){
console.log(result);
});
When resolved, State is passed down the chain
This allows easy chaining of promises:
function foo(){
return Promise.resolve('bar');
};
foo().then(function(result){
return result.toUpperCase();
})
.then(function(result){
return result.replace('R', 'T');
})
.then(function(result){
console.log(result);
});
brilliant
So why should I give a shit?
solve problems on the syntax level
avoid 'callback hell'
function serveDrink(order, callback){
findBottle(order, function(bottle){
openBottle(bottle, function(){
findGlass(function(glass){
fillGlass(glass, bottle, function(drink){
giveToCustomer(drink, function(){
callback();
});
});
});
});
});
}
When your async code uses promises, you can write:
findBottle(order)
.then(openBottle)
.then(findGlass)
.then(fillGlass)
.then(giveToCustomer);
Simplify error handling
function serveDrink(order, callback){
findBottle(order, function(err, bottle){
if(err) handleError(err);
openBottle(bottle, function(err){
if(err) handleError(err);
...
});
});
}
You can catch errors from anywhere in the chain:
findBottle(order)
.then(openBottle)
.then(findGlass)
.then(fillGlass)
.then(giveToCustomer, handleError);
Remove awkward PARALLELISM
var count = 0;
var onFinished = function(finishedFunc){
count++;
if(count == 2){
finishedFunc();
};
};
var order1 = serveDrink('rum', onFinished);
var order2 = serveDrink('vodka', onFinished);
We can use '.all' which resolves when all promises passed to it resolve
var order1 = serveDrink('rum');
var order2 = serveDrink('vodka');
Promise.all([order1, order2]).then(finishedFunc);
A common misconception
Promises were not designed to solve these problems.
They are merely a nice side-effect of modelling the problem
in a semantically different way.
Solve problems on the Semantic level
"The nature of promises is that they remain immune to changing circumstances"
Frank Underwood, House of Cards - 2013
Maintain encapsulation
Promises maintain state where callbacks do not:
- Registering a function guarantees it's execution.
- Order of execution is the order of registration.
Logger.prototype.logResult = function(promise){
return promise.then(function(result){
console.log(result);
}
}
This function has absolutely no knowledge of the action being
taken, but 'hooks in' to the chain without interfering with the result.
Composition in an async world
In a chain of synchronous calls, composing functions
and catching exceptions is easy.
Promises bring that ability to asynchronous calls.
Promises give us back functional composition and error bubbling.
functions for functions,
not flow control
A callback is using a function to control flow.
We can instead control the flow with promises;
leaving functions to do one thing, and do it well.
Promises in Practise
functional composition demo
Encapsulation / flow control demo
Promises in Action
Introducing
HTTPDeferred wraps a jQuery Deferred and is designed to
simplify error handling when working with a RESTful JSON API.
-
handle - Handle a given HTTP status code/codes
- unhandled - Handle only errors which don't have a handle or fail function
var updateName = API.updateName('will');
updateName.fail(function(reason){
var errorCode = reason.status;
if(errorCode == 400){
handleFormError(reason.responseText);
}
else if (errorCode == 403){
handleUnauthorisedUser(reason.responseText);
}
else if (errorCode == 500{
handleServerError(reason.responseText);
}
else {
// Success
}
});
var updateName = API.updateName('will');
updateName.handle([400], handleFormError);
updateName.handle([401, 403], handleUnauthorisedUser);
updateName.handle('5XX', handleServerError);
updateName.done(function(){
// Success
});
HTTPDeferred
In Summary
- A nicer syntax and interface for asynchronous code.
- Compose functions as if they were synchronous
- Abstract flow control out of our function logic
- Help us maintain separation of concerns.
Further reading
Promises. In theory and reality
By Will Demaine
Promises. In theory and reality
- 2,060