One of the new features in HTML5 allows asynchronous JavaScript operations to happen on the web freeing your UI thread to continue and not lock up the user providing a rich user experience. But how do you use AJAX along with the web workers to post data back to the server? This proves a little more difficult because we are limited to basic JavaScript calls. We can’t use jQuery from within the web worker, so we have to rely on our old friend the XMLHttpRequest.

First let’s start with the basics, calling a web worker. In order to call a web worker you must create a separate JavaScript file to hold all the logic. I have the following code in a JavaScript file named SavePerson.js

   self.addEventListener('message', function (e) {
 
    self.postMessage('Saved person: ' + e.data);
});

In the main body of my JS code I have the following code to call the worker.

var worker = new Worker('/scripts/SavePerson.js');
 
worker.addEventListener('message', function (e) {
    alert(e.data);
});
 
worker.postMessage('James Bond');

As you may have noticed in order to send messages back and forth both the caller and the worker are posting messages back and forth and are listening for the message event. The event contains one parameter ‘e’ which has a data property. This data property can be just simple text or JSON. The caller, in this example, is passing the text “James Bond” to the worker. The worker receives the message and simply prepends the text ‘Saved person: ’ in front of the message and posts that back to the calling thread, who then pops up that message in an alert box.

This is obviously a very simple example and will return almost immediately, with very little lag. So this isn’t something you would generally use web workers for. You would want to use them for long running processes. Something like saving or updating a record doesn’t require the user to wait before it is finished.

I am now going to update my web worker to actually make a call back to my .Net code to do my insert.

self.addEventListener('message', function (e) {
 
    var data = JSON.stringify(e.data);
    
    var req = new XMLHttpRequest();
 
    req.open('POST', '/myHandler.ashx?action=SavePerson', false);
 
    req.setRequestHeader('Content-Type', 'application/json;  charset=utf-8');
    req.onreadystatechange = function () {
        if (req.readyState == 4 && req.status == 200) {
            self.postMessage({ 'Error': 'No', 'Message': 'Save Successful' });
        }    
    }    
    req.send(data);
});

This is a more complex example, so let’s step through one line at a time for those not used to the old school method of making AJAX calls. The first line is the same as our first example where we are listening for the message event. We are then converting the JSON data passed in into a string so can post it back to the server. We then create a new XMLHttpRequest object and open it. This is a post method since we are sending data back to the server. I am posting back to a generic handler named myHandler.ashx, and passing a query string value that is telling my handler what action I wish to take.

The last parameter of the open method is whether or not you want this synchronous or not. Since I am in a web worker which is in a separate thread already from the main UI thread I can wait around for my AJAX call to come back. The next line tells the server that I will be sending JSON back to the server. We are then ready to setup our callback event for the readyStateChange event. The state changes a few times during this process so we must look for the complete state, which is HTTP status of 200 and a ready state of 4 which equates to loaded. Once we have received those codes, we post a message back to the parent saying that there were no errors and the save was successful. The last line is where the post actually happens when we tell the XMLHttpRequest to send the data.

Whew, that was a lot of work for something so simple as calling $.post(“/myhandler.asxh?action=SavePerson”, data, function(){}) in jQuery. This is why jQuery is such a nice tool. Under the hood jQuery is doing the same thing, and since this worker is in a separate thread there is no document.ready function, so we can never initialize the jQuery object. That is why you can’t use it in your workers.

Calling the worker is exactly the same as in the first example except I am sending and receiving a JSON object.

 var person = {     'Name': 'James Bond',
                    'Age': '32',           
                    'Bio': 'Redacted',
                };  

 var worker = new Worker('/scripts/SavePerson.js');
        
        worker.addEventListener('message', function (e) {            
            if (e.data.Error == 'No') {                
                DisplayInfoMessage(e.data.Message);             
            }
            else {                
                DisplayErrorMessage(e.data.Message);
            }            
        });

worker.postMessage(person);        

Summary

  • Web workers allow async JavaScript calls to free up your UI thread
  • You should only use them for long running processes
  • You can pass strings or JSON between worker and caller
  • You can’t use jQuery in your workers
Tagged with: