Using JavaScript Promises in Lightning Components

With JavaScript being a single threaded process by nature, using "JavaScript Promises" it makes JavaScript to be a multithreaded or in other words it is a process of making Asynchronous calls using JavaScript.

JavaScript Promises is a native JavaScript functionality that can be used in Lightning Components. Salesforce recommends using ECMAScript 6 (ES6, often referred to as “Harmony”) which is a standard script language. In case if the browser doesn’t provide a native version, the framework uses a polyfill so that promises work in all browsers supported for Lightning Experience.

Basic Syntax for Promises:

var promise = return new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise can return either resolve (If the result is success) and reject (If the result is fail). Optionally there is one more status called pending. Now let's go ahead and build a simple Lightning Component that will output some user information like current device/timzone.

JsPromises.cmp: Component file
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <!--Handler to call controller code upon component load-->
    <aura:handler name="init" value="{!this}" action="{!c.myPromise}"/>
    
    <div>
        <center><ui:message title="JavaScript Promises." severity="confirm" closable="false"/>
        </center>
    </div>    
</aura:component>

JsPromisesController.js: Controller.js file to call helper method that uses Promises to return user information.

({ /*Controller method*/
    myPromise : function(component, event, helper) {
        // Get variable value from helper
        var loadPromise = helper.promiseHelper1(component);
        
        console.log('Return value from helper: ' + loadPromise);
        // Assign return value to the component attribute
        component.set("v.data", loadPromise);
        
        // Call helper method that returns promise results
        var userDetails = helper.promiseHelper2(component, loadPromise);
    }
})

JsPromisesHelper.js: Helper.js file to return user information using JavaScript Promises.

({  /*Helper method*/
    promiseHelper1 : function(component) {
        console.log('Helper called');   
        var loadPromise = true;
        return loadPromise;
    },
    /*Helper method*/
    promiseHelper2 : function(component, loadPromise) {
        // returning promise results
        return new Promise(
            function (resolve, reject) {                
                if (loadPromise) {
                    // Return user information upon resolve
                    var device = $A.get("$Browser.formFactor");
                    var timeZone = $A.get("$Locale.timezone");
                    var language = $A.get("$Locale.language");
                    var isPhone = $A.get("$Browser.isPhone");
                    
                    var userDetails = {
                        Currentdevice: device,
                        currentTimeZone: timeZone,
                        currentLanguage: language,
                        isThisPhoneDevice: isPhone
                    };
                    resolve(userDetails); // resolve result
                    console.log(userDetails);
                } else {
                    // Return exception upon reject
                    var reason = new Error('Exception occured!');
                    reject(reason); // reject result
                    console.log(reason);
                }               
            }
        );
    }
})

Below is a simple app that is going to use above Lightning Component and display results under console.

<aura:application extends="force:slds">
    <c:JsPromises/>
</aura:application>

Now once I use preview from the above App, it should open up a new page to display our Lightning Component and on that page if we use inspect pane by navigating using right_click-->Inspect we should be able to view results.


Chaining Promises

One more advantage of using Promises is that it can be chained to process multiple routines in Asynchronous way. Let's go ahead and extend above Lightning Component to implement Promise chaining.

JsPromisesController.js: In this file we are using a variable to call helper methods using chaining promises. The way we chain promises is by using ".then" annotation.

({ /*Controller method*/
    myPromise : function(component, event, helper) {
        // Calling helper method for getting boolean value
        var loadPromise = helper.promiseHelper1(component);
        
        console.log('Return value from helper1: ' + loadPromise);
        
        // Calling helper method to log user details
        var userDetails = helper.promiseHelper2(component, loadPromise);
        
        // Chaning promises
        var displayUsrDetails = function() {
            // log message before chaining
            console.log('Before promise chaining');
            
            userDetails
            
            .then(function() {
                helper.promiseHelper3(component)              
            })            
            .then(function (fulfilled) {
                console.log('From Fulfilled');
                console.log(fulfilled);
            })
            .catch(function(error) {
                console.log(error.message);
            })
            // log message after chaning
            console.log('After promise chaining');          
        };
        displayUsrDetails();        
    }
})

JsPromisesHelper.js: In this file we have added an additional method that returns some message and just to note we are just returning resolve response here.

({  /*Helper method*/
    promiseHelper1 : function(component) {
        console.log('Helper called');   
        var loadPromise = true;
        return loadPromise;
    },
    /*Helper method to return user details using promises*/
    promiseHelper2 : function(component, loadPromise) {
        console.log('Boolean value: ' + loadPromise);
        // returning promise results
        return new Promise(
            function (resolve, reject) {                
                if (loadPromise) {
                    // Return user information upon resolve
                    var device = $A.get("$Browser.formFactor");
                    var timeZone = $A.get("$Locale.timezone");
                    var language = $A.get("$Locale.language");
                    var isPhone = $A.get("$Browser.isPhone");
                    var userDetails = {
                        Currentdevice: device,
                        currentTimeZone: timeZone,
                        currentLanguage: language,
                        isThisPhoneDevice: isPhone
                    };
                    resolve(userDetails ); // resolve result
                    console.log(userDetails);
                } else {
                    // Return exception upon reject
                    var reason = new Error('Exception occured!');
                    reject(reason); // reject result
                    console.log(reason);
                }               
            }
        );
    },
    /*Helper method to return some message*/
    promiseHelper3 : function(component) {
        var userMessage = 'Is this an Android device: ' +
            $A.get("$Browser.isAndroid") + '. Is this a Tablet: ' + 
            $A.get("$Browser.isTablet");
        alert(userMessage);
        // This promise is returning only resolve response
        return Promise.resolve(userMessage);
    }
})

Output: If we notice the output here the console.log statements for 'Before promise chaining' and 'After promise chaining' are printed next to each other where as in the code we have multiple calls to helper methods in between them which are expected to get logged. But JavaScript Promises being Asynchronous, this is how they process to work!



Resource Reference Links:
  • Using Promises/Lightning Components Developer Guide
  • JavaScript Promises for Dummies by Jecelyn Yeen: In this blog JavaScript Promises are explained very nicely.
  • Introduction to JavaScript Promises: This is the Salesforce recommended post for learning more on JavaScript Promises.


  • Thank you!

    Comments

    Popular posts from this blog

    Displaying Toast Message from Modal in Lightning Components

    Lightning RecordForm - An enhanced Lightning Data Service

    Lightning Component to display dynamic sObject data