Introduction to the Javascript Promises

A promise is a method that eventually produces a value. It can be considered as the asynchronous counterpart of a getter function. You can understand how it works with a simple example :

promise.then(function(value){
// Do something with value
});

JavaScript is only asynchronous in the sense that it can make, for example, Ajax calls. The code will stop executing until the call returns (successfully or otherwise), at which point the callback will run synchronously. No other code will be running at this point.

Thanks to the Promises API , developers are able to avoid a lot of callbacks (just taking a callback or passing a callback doesn't mean it's asynchronous) to handle async interactions, which now can be handled as any other variable.

Promises can replace the asynchronous use of callbacks, and they provide several benefits over them. They start to gain ground as more and more libraries and frameworks embrace them as their primary way to handle asynchronicity. Since 2013, the promises are natively supported in the modern Browsers.

Why should i use promises

The promises will help you to make all the complex async code easier to handle, understand and maintain.

Promises are not about callback aggregation. That's a simple utility. Promises are about something much deeper, namely providing a direct correspondence between synchronous functions and asynchronous functions.

The javascript Promises represent the next great paradigm in JavaScript programming, but understanding why they are so great is no simple matter so please keep reading.

Creating your first promise

To understand the concept, we'll expose the most simple way to use a Javascript Promise.

The Promise constructor takes one argument, a callback (function) with two parameters, resolve and reject. Now inside the callback you need to execute all that you want do asynchronously, finally if everything worked correctly invoke the resolve function, otherwise the reject (error) function.

Note

Only 1 error callback will be triggered, either the function as second parameter of the then function or the catch callback, not twice.

Promise.resolve & Promise.reject

Sometimes, for different reasons you'll don't need to repeat an async task, i.e an ajax call which retrieves something and it can be stored in memory. That's when resolve and reject comes to play.

Use these methods to return the result of a promise without use the entire constructor (fulfilled or rejected).

var cacheUserAge = {};
function getUserAge(id){
// if user id is in the object
// do not fetch the result from the server
// return the local result instead
if(cacheUserAge[id]){
return Promise.resolve(cacheUserAge[id]);
}
// use Promise.reject to trigger the catch callback
return fetch('api/userage/' + id + '.json')
.then(function(data) {
// save it in the object
cacheUserAge[id] = data;
// return the value to the next then callback
return result;
}).catch(function() {
throw new Error('Could not get age: ' + id);
});
}
// Then use it
var userId = 15;
getUserAge(userId).then(function(age){
alert(age);
});

Note

The fetch api returns a promise.

Fulfilling multiple promises at time

The promise API allow you to solve multiple promises at time using the Promise.all method.

Promise.all takes an array of promises and creates a promise that fulfills when all of them successfully complete. You get an array of results (whatever the promises fulfilled to) in the same order as the promises you passed in.

Cross browser support

Polyfill

As mentioned before, the introduction of the API doesn't cover out-dated browsers, but there are many polyfill implementations available for use. You can see a top 5 of the best promises polyfill here. Most of the polyfill cover all the possible scenarios of the API, however there is a limitation in IE9 which can be easily solved using a different syntax.

catch is a reserved word in IE<9, meaning promise.catch(func) throws a syntax error. To work around this, you can use a string to access the property as shown in the following example :

promise['catch'](function(err) {
// ...
});
// Or just use the second paramer of then instead of using catch
promise.then(undefined, function(err) {
// ...
});

Note

Such technique is already provided by most common minifiers, making the resulting code safe for old browsers and production. However, to prevent any possible incompatibility, use the second parameter of the then function instead of use catch.

There are plenty of implementations of promises available to developers. For example, jQuery's Deferred, Microsoft's WinJS.Promise, when.js, q, and dojo.Deferred. However be aware of which you use as not all of them follow the standards, jQuery's implementation does not quite fulfill the Promises/A spec in the way that most of the other implementations do.