Using Javascript promises within Lightning Components

My new project requires a lot of javascript coding for Lightning component. Many books and guides about programming will teach you a basics but finally many of them just like that

ho to draw an owl

Author will give you a very basic example of use and leaves you alone. Lightning Components developer guide does it. Actually when they teaching about using asynchronous javascript in Lightning they shows how to use action.setCallback for just one server action in callback stack. But what should you do if you need to call server action, then analyse the response and based on this response to make another server callout or few? Probably you can write some callBack Hell code

promises-and-chaining-in-angularjs-into-callback-hell-and-back-again

Let consider for our test case the following requirements:

  • run server function 1 and wait for response
  • if server returned 1 then call server function 2
  • do some stuff based on server function 2 response

Something like that

var action = cmp.get("c.serverAction");
action.setCallback(this, function(response){
    var state = response.getResponse();
    if (state === "SUCCESS") {
        if (response.getReturnValue() === someCheckedValue) {
            var action2 = cmp.get("c.serverAction2");
            action2.setCallback(this, function(response2) {
                var state2 = response2.getResponse();
                if (state2 === "SUCCESS") {
                    if (someCondition) {
                        var action3 = cmp.get("c.serverAction3");
                        action3.setCallback(this, function(response2) {
                            // you can check how deep the rabbit hole goes by adding a few callbacks
                        })
                    }
                }
            }
        })
    } else {
        console.error("Failed!");
    }
});

I pretty sure that you can't name this code maintainable and flexible. Actually when you add some business logic and error handling within these function you will find that you stack of callbacks takes a 150-200 LoC. Not so good.

Here’s an option to use JavaScript promises (David Walsh’s post)

// CONTROLLER ——–
var someFunc = function() {
    // runAsync is a function which returns Promise
    runAsync().then(
        function(response) {//onSuccess
            if (response["status"] === 1) {
                helper.callServerAction2(cmp);
            } else if (response["status"] === 2) {
                helper.callServerAction3(cmp);
            } else if (response["status"] === 3) {
                helper.callServerAction4(cmp);
                helper.callServerAction5(cmp);
            }
        },
        function(error) {
            //onError
            console.error("Failed!", error);
        }
    );
}

// HELPER ——–
var runAsync = function(cmp) {
    var action = cmp.get("c.serverAction");
        // here’s a first trick – you need to call another helper method through this
        // but in context of Promise ‘this’ will be different
        var ltg = this;
        return new Promise(function(resolve, reject){
            // do some Asynchronous action here
            action.setCallback(ltg, function(response) {
            var state = response.getState();
            ltg.callSomeHelpeMethodFromPromise();
            if (state === "SUCCESS") {
                resolve(action.getReturnValue());
            } else {
                reject(state);
            }
        });
    });
}

So, as you can see from the code above using of Promises makes your code much modular and flexible to change. This’s a reason why you need to use Promises in your code. If you using jQuery in your project you can see to jQuery Deferred Objects which does the same but have a little bit easy API.

Thanks for reading

[javascript][lightning][lightning components][promises][salesforce]