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

If you want to keep the user interface fast and responsive you have to follow the framework and create asynchronous functions - but how? This sounds complicated. The solution is to make use of Web Workers and wrap what you create so that it returns a promise. Let's see how it all fits together.

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


cover


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

 


A Slow Calculation

First let's start off with an example of a long computational task just asking to be implemented on a separated thread.  For the sake of simplicity the calculation is to sum a large number of integers and return the total.

function mySlowCalculation() {
     var total = 0;
     for (var i = 0; i <= 10000000; i++) {
          total += i;
     };
     return total;
  };

Of course in practice your task could be doing all sorts of interesting things that take a long time. You may also have to adjust the size of the for loop to take account of how fast your machine is.

To see this in action before you have moved it off to another thread add a button with id Button1 and perhaps a second button that does nothing that you can attempt to click to prove that the UI is frozen.

<button id="Button1">Click to start </button>
<button>dummy button</button>

Now we can call the slow function when the button is clicked and to show that it has completed its work we can set the button's text to the result:

Button1.addEventListener("click", function (e) {
   Button1.textContent = mySlowCalculation();
  });

If you run this you will discover that when you click the button nothing works until the answer comes back from the function and is displayed on the button. If it all happens too quickly or slowly then change the number of loops.

Clearly this freezing of the UI is not good and this is the reason we need to use a separate thread for the calculation - or any task that takes similar amounts of time.  That is we need a Web Worker.

Basic Web Worker

The good news is that Web Worker is very easy to use. What is slightly difficult is working out what you are not allowed to do and achieving simple communication between the threads. Ideally you should wrap any Web Worker tasks you create as promises so as to fit in with the rest of WinJS and to make your own code easier to use. But first let's take a look at how you make use of the worker object to implement another thread and then see how to package it as a function that returns a promise.

The worker object automatically starts a new thread and begins executing JavaScript code as soon as it is created. The JavaScript has to be stored in a separate file and the easiest place to use is a project folder. You can even create a suitable file in the js folder by right clicking and selecting Add,New Item and then Dedicated worker in the dialog box that appears.

 

workerfile

 

You don't get much for your trouble - just a single event handler stub. What this is used for will become apparent later. For the moment any JavaScript .js file stored in the js folder will do.

The basic action of a worker is that it loads a JavaScript file that you specify in its constructor and it loads and starts the script executing on a new thread. So for example, if you have a program stored in myScript.js the instruction:

var worker=Worker("myScript.js");

the code stored in myScript.js is running on a thread that is different from the UI thread and you have a Worker object created on the UI thread that allows you to interact with it.

First some basic rules.

The new thread cannot access any objects that the UI Thread can. This means it cannot interact with any global objects and it cannot interact with the DOM or the user interface in any way.

This may seem a little restrictive but it is a restriction that is necessary to make sure that the two threads you now have don't try to access the same object at the same time. If this was allowed to happen you would need to introduce a lot of complicated machinery - locks, semaphores and so on - to make sure that the access was orderly and didn't give rise to any very difficult to find bugs - race conditions, deadlock and so on.

in other words the Web Worker has big restrictions so that you can use it without complication and without any danger.

For most purposes it is sufficient and hence very effective.

Web Workers do have access to all of the global core JavaScript objects that you might expect. The rule is that if the object could be shared in anyway with the UI thread then you cannot get access to it.

To make up for this restriction there are two new objects that the Web Worker can access - WorkerNavigator and WorkerLocation. The navigator provides basic information about the app's context - the browser in use, appName, appVersion and so on. The location object provides details of where the app is in terms of the current URL

if these two objects don't provide enough information you can easily arrange to pass the worker thread additional data of your choosing.