Click here to Skip to main content
15,886,578 members
Articles / All Topics

JavaScript Promises

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
15 Jun 2015CPOL4 min read 5.5K   1   1
JavaScript Promises

JavaScript Promises are a feature of ECMAScript 6 (aka ES6), the new version of JavaScript scheduled for release in the not too distant future. However, the feature has already been written, in some form, into a number of browsers including IE12, Chrome (32+) and Firefox (25+).

But what exactly are Promises in JavaScript, and why should we be interested in them?

Put simply, ‘Promise’ is a JavaScript class (constructor function) which helps us to write code involving asynchronous operations.

To help us understand the concept of Promise objects (instances of the Promise class), it is helpful to think of them as indeed representing ‘promises’ in the traditional sense of the word. So then, who is it that is making these promises, to whom are they being made, and what are they promising?

Before answering these questions, let's first take a step back and remind ourselves what asynchronous programming is and why it is important in JavaScript.

If you think of an asynchronous operation in JavaScript (or indeed any language), it typically consists of one function calling another function without having to wait for its return (that is, without being blocked). This capability is especially important in JavaScript, a single-threaded language in which, and in web pages that single thread is also responsible for handling user input. If your JavaScript code needs to call some function which takes a while to complete, then your browser will freeze until it is done, unless of course you can call it asynchronously.

To meet this need, JavaScript programmers have traditionally used callbacks to implement asynchronous programming. One function which has been used a great deal in recent years is the jQuery.ajax() function, which performs an asynchronous HTTP request. Since jQuery v1.5, you can make use of Promises when calling the jQuery.ajax() function (more on this later), however prior to this it was necessary to use callbacks to achieve asynchronicity.

For example:

JavaScript
$.ajax({
    type: 'POST',
    url: myUrl, // myUrl defined somewhere else
    data: myData,
    success: function(data) { // success callback function
        alert(data);
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) { // error callback function 
        alert("Status: " + textStatus); alert("Error: " + errorThrown); 
    } 
});

Here, we pass success and error functions as callback arguments, to be executed if the operation succeeds or fails respectively.

At this point, we can reconsider the ‘promise’ that is being made here.

As is so often the case in programming, it is helpful to think of things in terms of a client-service relationship. Think of the calling code here as the client, and the code responsible for performing the asynchronous operation as the service (in this case, a service being offered an HTTP server). When we send our request to the service, an implicit promise is made to us (the client) by the service. It promises to fulfil our request, and if it keeps its promise the success callback function will be called. However, promises are sometimes broken, and if the service breaks its promise (perhaps the server database is down), then the error callback function is called. To summarise then:

In a typical asynchronous programming scenario, a ‘client’ sends a request to a ‘service’, and the service promises to fulfil the request. The client can adjust its behaviour depending on whether the service keeps or breaks its promise.

Hopefully, you can now begin to see how a kind of promise is being made here, by the service, to the client. Now let’s take a look at an example using the Promise class:

JavaScript
function doSomething(){ // sometimes this will return true, sometimes false               
    return Math.floor(Math.random()*11) > 5;               
}
        
var promiseMeThis = new Promise(
    function(resolve, reject) {
        window.setTimeout(function() { // wait 3 secs then get result
            var promiseKept = doSomething();
        
            if(promiseKept)
                resolve();
            else
                reject();
            }, 3000);
        }
).then(function(){
        alert('promise fulfilled!');
}).catch(function(){
        alert('promise broken (rejected)!');
});

The main point to note here is how we are chaining function calls together, rather than passing the actual callback functions into the Promise constructor. The then() function allows us to set a ‘success’ callback, and the catch() function allows us to set an ‘error’ callback. Each of these functions returns a Promise object, thus allowing us to chain function calls together in the manner shown.

But why? How is this approach any better than the old-fashioned way?

In a simple scenario, there is not much difference, however as our asynchronous requirements become more complex, the Promise approach offers much simpler solutions.

Consider an example where we need to call a function asynchronously, and then if that succeeds call another, and then another, and so on. In the old world, the code might look something like this:

JavaScript
$.ajax({
    type: 'POST',
    url: myUrl,
    data: data1,
    success: function (data2) {
        $.ajax({
            type: 'POST',
            url: myUrl2,
            data: data2,
            success: function (data3) {
                $.ajax({
                    type: 'POST',
                    url: myUrl3,
                    data: data3,
                    success: function (data4) {
                        alert(data4);
                    },
                    error: 
                       function (XMLHttpRequest, textStatus,errorThrown){                                                 
                        alert("Status: " + textStatus);
                        alert("Error: " + errorThrown);
                    }
                });
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {                                
                alert("Status: " + textStatus);
                alert("Error: " + errorThrown);
            }
        });
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {                
        alert("Status: " + textStatus);
        alert("Error: " + errorThrown);
    }
});

Not very readable, is it? And this is with only 3 consecutive ajax calls. And what are you supposed to do if you only want one of your error callback functions to be called? There is no obvious or simple solution without Promises.

Compare this to a similar scenario using Promises:

JavaScript
function doSomething() { // sometimes this will return true, sometimes false               
    return Math.floor(Math.random() * 11) > 1;
}

var promiseMeThis = new Promise(

function (resolve, reject) {
    window.setTimeout(function () { // wait 1 sec then get result
        var promiseKept = doSomething();

        if (promiseKept) resolve();
        else reject();
    }, 1000);
}).then(function () {
    window.setTimeout(function () { // wait 1 sec then get result
        var promiseKept = doSomething();

        if (promiseKept) resolve();
        else reject();
    }, 1000);
}).then(function () {
    window.setTimeout(function () { // wait 1 sec then get result
        var promiseKept = doSomething();

        if (promiseKept) resolve();
        else reject();
    }, 1000);
}).then(function () {
    alert('promise fulfilled!');
}).catch (function () {
    alert('promise broken (rejected)!');
});

Not only is this much clearer about what it is trying to achieve, but the error callback function will only be called once if any of the asynchronous operations fail.

I mentioned earlier that since jQuery v1.5 we can in fact make use of Promises when calling the .ajax() function. This is because this function now returns an object which implements the Promise interface, and we can achieve its behaviour by using functions such as .done() and .fail(), which as you might have guessed return Promise objects themselves (i.e. objects which implement the Promise interface).

So we can now write the .ajax() example from above as follows:

JavaScript
$.ajax({
    type: 'POST',
    url: myUrl,
    data: data1
}).done(function(data2){
    $.ajax({
        type: 'POST',
        url: myUrl2,
        data: data2
    });
}).done(function(data3){
    $.ajax({
        type: 'POST',
        url: myUrl3,
        data: data3
    });
}).done(function(data4){
    alert(data4);
}).fail(function (XMLHttpRequest, textStatus, errorThrown) {                
        alert("Status: " + textStatus);
        alert("Error: " + errorThrown);
});

Much nicer.

The post JavaScript Promises appeared first on The Proactive Programmer.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMy vote of 5 Pin
raddevus7-Nov-18 3:52
mvaraddevus7-Nov-18 3:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.