WinRT JavaScript - Promises
Written by Ian Elliot   
Article Index
WinRT JavaScript - Promises
An Example Promise
Custom Promises

WinRT is mostly an asynchronous system and making the best of this is a matter of using the promise object. The promise object makes asynchronous code easy to use and easier to create. Promises are a proposed JavaScript standard.

This article is Chapter 9 of  Creating JavaScript/HTML5 Windows 8 Applications.

cover


If you have missed any of the earlier ones they are:

 

 

 

JavaScript is single threaded and this means if you were to call any functions that needed to wait while some external event occurred - a file to download say - then for the duration of the even your app would appear to freeze. The user interface and events in particular are all handled by the same thread and if that thread is in a wait state then nothing else gets done.

The usual solution to this problem is to use a callback function. The callback is passed to the function that is going to do the long job and instead of keeping the thread waiting it simply returns immediately. This allows the thread to do other work while it get on with its task. When it has finished it calls the callback function, usually with the result of the task. The callback function then processes the results.

Callbacks are difficult because they alter the flow of control in an unnatural way. What you want to do is:

Task A
Task B - long running
Task C - processes the result of Task B
Task D - nothing to do with the result of Task B

But if you do the tasks in this way the everything hangs when you start task B because the UI thread isn't able to do anything else. To keep things responsive what you have to do is convert Task C into a callback and make Task B return before it is complete. The program now looks like:

Task A
Task B - long running but returns at once with callback C
Task D - nothing to do with the result of Task B

Task C - processes the result of Task B

The callback is now positioned out of the line of the natural flow of control. You think of the program as being do A, do B, do C and then do D but you really don't know when C will be executed and most likely it will be after D.

Asynchronous programming is messy and it gets messier as you use more and more asynchronous calls but you have to approach things in this way or accept that your application will come to a halt every now and again. WinJS and WinRT in general is strongly asynchronous in the sense that most system calls return at once if there is even the slightest possibility of keeping the UI thread occupied. 

Asynchronous programming is unavoidable.

Promises are a way of trying to make asynchronous programming easier and all of the asynchronous WinJS functions make use of promise objects as an alternative to callbacks.

Let's look first at the basic operation of a promise.

Using A Promise Object

A operation that will takes some time will generally return a promise object at once:

var mypromise=slowFun(args);

Notice that even though you get a promise object returned at once it is unlikely that slowFun has finished whatever it is trying to do. There is also the idea that the slow function is computing a value which your program is waiting for - this isn't necessarily the case as you could be just waiting for it to complete what it is doing.

What do you do with a promise?

The most common thing to do is to use its then method to setup what should happen when the slow function is complete.

mypromise.then(onComplete,onError,onProgress);

where onComplete is a function that is called when the slow function finished its task. It is passed the value that the slow function generates on completion. The onError function is option and is called if an error occurs while the slow function is executing. The onProgress function is called periodically to indicate progress - not all promise objects support this. Also you only have to specify an onComplete function if you don't want to handle error or monitor progress.

For example the WinJS.UI.processAll function could take some time to complete the processing of the UI and so it returns a promise object. If you want to do some processing after the processAll function completes you should define an onComplete function:

var mypromise = WinJS.UI.processAll();
            mypromise.then(function (value) {
                console.log("Finished");
                console.log(value);
            });

You will see the message printed in the JavaScript console and the value is:

[object HTMLBodyElement]

This is the default starting point for processAll to scan through the DOM.

One of the problems with trying to find out what functions return as their final result is that usually the documentation just gives the fact they return a promise object with no mention of what the final value is.

Notice that you can add the functions to a promise object anytime you want to. If the promise object has entered the completed state then the onComplete function will be called as soon as you provide it - there is no rush to define the function for fear it might miss an event.

Also, although you can write the code as above, it is usual to not store the promise object and simply call the then method as in:

WinJS.UI.processAll().then(function (value) {
                console.log("Finished");
                console.log(value);
});

 

It is also worth remembering that the functions defined within a then method are closures and so have access to the variables that are in scope at the point at which the function is defined.