Asynchronous programming in JavaScript (HTML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

JavaScript is a single-threaded language. This means that invoking a long-running process blocks all execution until that process completes. UI elements are unresponsive, animations pause, and no other code in the app can run. The solution to this problem is to avoid synchronous execution as much as possible.

One way to do this is to have a function execute at a later time, as with event handlers, which are invoked after another call has raised an event. Callback functions are another kind of asynchronous processing, because they call back into the code that initiated the process.

Problems when using asynchronous programming

Asynchronous programming can quickly become complicated. Many of the standard JavaScript APIs rely heavily on callbacks, which are often nested, making them difficult to debug. In addition, the use of anonymous inline functions can make reading the call stack problematic. Exceptions that are thrown from within a heavily nested set of callbacks might not be propagated up to a function that initiated the chain. This makes it difficult to determine exactly where a bug is hidden.

Asynchronous programming in Windows Runtime apps that use JavaScript

Windows Runtime and Windows Library for JavaScript provide a way to overcome these problems by implementing the Common JS Promises/A proposal. A promise object returns a value at some time in the future. You can use these objects to construct chains of asynchronous code that are easier to read.

All of the Windows Runtime APIs that are exposed to Windows Store apps are wrapped in promise objects. This allows you to use Windows Runtime APIs in a way that you're comfortable with. The promises in WinJS are important because many interactions with Windows Runtime are asynchronous.

Promises explained

A promise is an object. The most frequently used method on a promise object is then, which takes three parameters: a function to call when the promise completes successfully, a function to call when the promise completes with an error, and a function to provide progress information. In both the Windows Runtime and the WinJS you can also use the done function, which takes the same parameters. The difference is that in the case of an error in processing, the then function returns a promise in the error state but does not throw an exception, while the done method throws an exception if an error function is not provided.

Let's look at a basic example of a promise with two (made-up) asynchronous methods, one to call a web service and another to store the results in a database.

myWebService.get("http://www.example.com")
    .then(function(result) { 
        return myDb.add(result); 
    })
    .then(function() {
        console.log('data successfully saved');
    }, function(error) {
        console.log('an error occurred while saving:');
        console.dir(error);
    });

You append the then function to the myWebService.get method. Since this method returns a promise, you can append a second then function to the myDb.add method, and handle any errors in the error function you pass to the second then function.

You can also group multiple promises. For example, you can use the join function to run multiple asynchronous operations that call several web services and then aggregate the results.

function loadData() {
    var urls = [
        'http://www.example.com/',
        'http://www.example.org/',
        'http://www.example.net'
        ];
        
    var promises = urls.map(function (url) {
        return myWebService.get(url);
    });

    WinJS.Promise.join(promises).then(function () {
        //do the aggregation here.
    });
}

First we create an array of URLs, then we use the Array.map function to convert the array of URLs into an array of promises (because mywebService.get returns a promise). Finally, we use the join function, which accepts an array of promises and returns a new promise after all of the promises have completed. We do the data aggregation inside the complete function of the then method.

Quickstart: Using promises

How to handle errors with promises

Troubleshooting WinRT errors

Chaining promises

Handling multiple promises