WinRT JavaScript - Web Workers & Promises
Written by Ian Elliot   
Article Index
WinRT JavaScript - Web Workers & Promises
Communication
Promises to the rescue

Promises

There is no doubt that the best way to package a worker thread is as a promise. This isn't difficult but there are are some subtle points and it is easy to become confused. It is important to understand promises before you try and make sense of the next section - so if your at all unclear read the previous chapter first.

To wrap a long running function that uses a worker thread as a promise, all we have to do is arrange create a function that returns a promise object. The interesting thing is that the worker code doesn't need any changes from the previous example. It simply computes the answer and then uses the postMessage method to trigger a message event on the UI thread and to return the result.

All of the new code is in the UI thread. We need a new function mySlowFunc that accepts the number of iterations as a parameter and returns a promise object:

var mySlowFunc = function (number) {
    var mypromise = new WinJS.Promise(

The first parameter of the promise object is a function that has three more parameters - complete, error and progress which are functions called when the thread is complete, has an error or regularly as a progress update respectively. Notice that all of these functions are UI thread functions.

   function (complete, error, progress) {

This function has to perform all of the initialization of the thread and generally do what is required to get it going:

var worker = Worker(
         "ms-appx:///js/worker.js");
worker.postMessage({ number: number });

Now we have a worker thread computing the result over some length of time and what we have to do to make sure that the UI is free to get on with its job is to bring this function to an end and return the promise object. However this doesn't solve the problem of calling the complete function when the thread has finished.

How can we do this so that the UI thread isn't blocked?

The answer is exactly as we have done it before - we set up an event handler for the message event:

worker.addEventListener("message",
 function (e) {
      complete(e.data.total);
 });
});

Now when the worker thread is complete it just calls the complete function with the result of the computation. In this case the result is just a simple value but in general it could be an object with lots of values.

Finally we return the promise object.

  return mypromise;
};

Notice that at this point the worker thread hasn't finished and the promise doesn't have a value as yet. It only gets the value when the work thread finishes and triggers a message event which calls the event handler.

The complete code for the function is:

var mySlowFunc = function (number) {
  var mypromise = new WinJS.Promise(
   function (complete, error, progress) {
    var worker = Worker(
              "ms-appx:///js/worker.js");
    worker.postMessage({ number: number });
    worker.addEventListener("message",
      function (e) {
            complete(e.data.total);
      });
    });
  return mypromise;
};

 

So how do we use the new function and the promise object it returns?

The answer is that you use it just like any other asynchronous function.

Button1.addEventListener("click",
 function (e) {
   Button1.disabled = true;              
   mySlowFunc(1000000).then(
       function(value){
         Button1.textContent = value;
         Button1.disabled = false;
       });
  });

The button's event handler now just has a simple call to mySlowFunc and this immediately returns a promise object  The then method of the promise object is used to define what should happen when the thread completes and returns the "promised" value. That is the function passed to then sets the button caption to the value and re-enables the button.

This is very easy to use and not that much more difficult to setup.

The key idea is that the function that does the calculation runs on the worker thread. The promise and function that returns it run on the UI thread. The UI thread is freed by the function that returns the promise because it sets an interrupt handler that will be called when the worker thread has finished.

Always wrap your long running functions as promises.

 

 cover

 Creating JavaScript/HTML5 Metro Applications

 

 

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, Facebook, Google+ or Linkedin,  or sign up for our weekly newsletter.