WinJs

WinJS Promises

For a while now I wanted to dive a little deeper into Promises, so I decided to write this tutorial.

For this tutorial I used the WinJS version as available on GitHub. If you want to follow along you’ll have to compile the code yourself. Which is very easy, but if you have any issues or questions please let me know and I’ll do a tutorial on that.

What’s a “promise”?

A promise is an object representing a value that is eventually returned by an operation. This object can be passed around like any other object.

Various frameworks have various implementations of promises. Promises are specified in the CommonJS Promises/A proposal. jQuery for examples uses Deferred. WinJS has its own implementation, but they basically work the same. You do something, and specify what happens then and then, until you are done.

The promise object has two functions you’ll use very often.

  • Then() à Allows you to specify what needs to be done when the promise is fulfilled. It also allows you to specify what to do when an error occurs and provide notifications on the progress.
  • Done()à Is almost similar to then, except it returns undefined instead of a promise. It is meant to be used at the end of the promise chain. It takes the same parameters, although unhandled exceptions need to be handled outside the promise chain and won’t be handled inside.

You will use the constructor a lot too. This can wrap some code in a promise and lets you handle the moment it is fulfilled.

Use a promise

One very common use of a promise in WinJS is its xhr() function. This function wraps the XMLHttpRequest in a promise and is used to make ajax calls. When given a URL and a response type the xhr() function returns a promise that is fulfilled when the call is completed, either by returning the data requested or when I fails and returns an error.

Let’s have a look at some code.

// create request object 
var request = 
{
    url:"https://gdata.youtube.com/feeds/api/users/paulsoaresjr/playlists?v=2&alt=json",
    responseType:"json"
};

//call to xhr
WinJS.xhr(request)	
    .then(function(r){
        var response = JSON.parse(r.response);
        console.log(response.feed.entry[0].title.$t);
    });

On lines 2 through 6 I create a request object. In this case I’m going to make a call to the YouTube API to request the playlists for a specific user. I specify I’d like the response to be JSON, both in the URL to YouTube and in the response type.

On line 9 I use the request object as a parameter in the xhr function. This function will make the call and returns a promise.

On line 10 the returned promise used immediately and its then function is called. As a parameter the then function takes up to three parameters, all three functions. The first, which is called when the promise is fulfilled successfully. The second parameter is a function the will be called when an error occurs. This allows you to handle the error and have the chain continue. The third function that can be passed to the promise function is used to handle the progress. Promises are not required to use progress.

Lines 11 and 12 parse the response and log the title of the first playlist to the console.

A more interesting situation

The service called in the previous examples returns the playlists for the specified user. But, say we want to know more about all these playlists. We’ll have to iterate over the lists of the playlists returned and make a new call for each playlists. When this is done we need to handle the results.

Promises are a big help in cases like this. Because promises are just objects we can create arrays of them. And the promise type has a function to join an array of promises to be handled as one.

Let’s change to code to the following:

WinJS.xhr(request)
    .then(function(r){
        var response = JSON.parse(r.response),
            promises = [];
        for (var i = 0; i < response.feed.entry.length; i++) {
            promises.push(WinJS.xhr({
                url:response.feed.entry[i].link[2].href+"&alt=json",
                responseType:"json"
           }));
        };
        return WinJS.Promise.join(promises);
    })
    .then(function(x){
        var playlistResult = [];
        for (var i = 0; i < x.length; i++) {
            var response = JSON.parse(x[i].response);
                playlistResult.push({
                    title: response.entry.title.$t,
                    summary: response.entry.summary.$t,
                    url: response.entry.link[1].href
                })
            };
            return playlistResult;
        }, function(err){
               console.log(err);
           }
    ).then(function(r){
        //do something with results from r[]
    });

The request object used as parameter in the xhr function on line 1 is the same object used in the previous sample.

Line 5 through 10 loop over the entries returned from YouTube. Per entry a new promise is instantiated (line 6) and added to the promises array.

The real magic happens on line 11. On this line the complete array of promises is joined into one and returned. After this, the next then function is called when all these promises are fulfilled. An array with results, one item per request, is passed to it.

Inside the then on line 13 I loop over this results, parse them and add them as a new object into an array if playlist results. At the end of the function at line 23 I return this array so it can be processed further into another then or done.

I also added a handler for the errors on line 24. This way I know when something went wrong here.

One major downside to this technique is that the whole chain fails whenever one promise returns an error.

Custom promises

Often you have to work with 3rd party libraries that don't use these promises. Wrapping existing code into a new promise.

First, let's look at same code again. This code replaces the last then of the previous sample.

.then(function(playlists){
    return new WinJS.Promise(function(complete, error){
        someRandomLibrary.magic({
            value:playlists,
            callback:function(x){
                complete(x);
            },
            error:function(err){
                error(err);
            }
        });
    })
});

The constructor of the promise on line 2 takes a function with 2 parameters. The promise uses these functions to keep the chain going. Both parameters are functions that you can call from your code. In this example I use call magic function of some random library. This function takes an object which has a callback and an error function. When magic call its callback function, I call the complete function that was given to me by the promise. This will trigger the next step in the chain of promises and call the then or done function if it is specified. The value passed to the complete function will be passed to the then or done functions. In case of an error occurring magic calls what I specified on line 8. I just call the error function that was provided to me, passing it the error. This way it can be handled somewhere else.

Wrap up

I hope I shed some light on these promises. Keep in mind that code like this can be refactored pretty easily into multiple methods, because promises can be passed around in variables and parameters.

A complete version of source is available on GitHub.

One comment

  1. Pingback: WinJS Promises

Leave a Reply

Seo wordpress plugin by www.seowizard.org.
%d bloggers like this: