JavaScript Threading - Part 2 (Worker)



In the second part of this series we're going to have a look at web workers.

Unlike timers a worker runs in an isolated thread, which allows us to run intensive tasks without blocking the UI/parent thread. This functionality is currently supported by organizations that care about developing real browsers (but will however be supported by Internet Explorer 10).

Note in chrome workers can't run locally (requires a webserver), unless you open chrome with the
--allow-file-access-from-files switch.


Lets have a basic look at how all of this works.

Observe the following snippet:

Snippet 1
var worker = new Worker('doWork.js');
 
worker.addEventListener('message', function(e) {
	alert(e.data); // Data received from client/worker thread
}, false);
 
worker.addEventListener('error', function(e) {
	alert(e.message); // something went wrong
}, false);
 
worker.postMessage('Hello Mars'); // Sending data to the worker thread
 

Firstly we need to create / instantiate a new worker object, you will notice that I passed a filename to its "constructor" - it points to the file / source code thats going to be executed within our worker thread. It is also possible to pass source code to it in the form of a blob url)

Notice that I attached a callback to the worker object's message event, this becomes necessary since the worker thread can't access objects living in the UI thread directly (thanks to thread-safety).

So you'll need to send messages between your threads, like seen on the last line of snippet 1 in which we send a message from our UI thread to our child/worker thread.

I also attached a callback to the worker's error event - allowing us to handle possible exceptions gracefully.

In the following snippet you can basically see what the file handling the worker thread will look like.

Snippet 2 - doWork.js
importScripts('some_file_you_might_need.js');
 
self.addEventListener('message', function(e) {
	// do some vicious work
	self.postMessage("From Thread - " + e.data); // post a message back to the parent thread
}, false);

Similarly to the first snippet, we need to attach a handler to the message event (to receive messages from the parent thread) and use the postMessage function to send results back to its parent thread.

Note like previously stated that you will not be able to access objects living in your parent thread, e.g document, window objects, you will however have access to a subset of its functions, like timer functions, XMLHttpRequest (ajax) and others.

You will also notice the function importScripts - like the name suggests it allows you to include external scripts within your js file.

Now all of this will only work within the page that created the worker, but awesomely enough its also possible to create a worker that can be shared among your pages - which will be the topic of the next part.




Post/View comments
 

JavaScript Threading - Part 1 (Timers)



In the first part of this series we're going to have a look at timers (setTimeout and setInterval functions).

Technically these functions are actually pseudo-threaded (looks like a dog, smells like a dog, barks like a dog, humps like a dog, not a dog) - they don't spawn new threads, but instead they cleverly get executed/queued on a single thread (along with other asynchronous events).

The first function we're going to look at is the setInterval function. This function accepts three arguments, of which the first one is a callback, the second an interval (in milliseconds) of when the callback will be executed.

The third argument is optional and sets the language (of the callback script I guess ?) - I've personally never used this argument, and can't see why any sane person would want to, can somebody enlighten us ? My guess is it's got something to do with the client-side vbscript days, allowing one to mix vbscript and JavaScript in Internet Explorer (puuuuukkkke) ?

In the following snippet we use the setInterval function to display the current time and update it every second (a basic time ticker).

Snippet 1
<div id="currentTime"></div>
<script type="text/javascript">
var timer = setInterval(
	function() 
	{
		var time = new Date().toLocaleTimeString();
		$('#currentTime').html(time); // assuming you're using jQuery
	}, 1000
);
</script>

Note that the value returned by this function can be used to stop the timer using the clearInterval function, e.g. "clearInterval(timer)".

It's also prudent to point out that our callback will automatically get re-executed irrespective of when/if the previous callback finished executing, so take care when putting code in your callback that can potentially exceed your interval, which brings me to our next timer function - setTimeout.

The setTimeout function has the exact same arguments as the setInterval function, the only difference however is that this function doesn't automatically continuously call its callback - which gives us a bit more control over our timer.

In the following snippet we use the setTimeout function to populate a div on our page via an ajax request (using jQuery).

Snippet 2
<div id="results"></div>
<script type="text/javascript">
 
	function GetResults() 
	{
		var timeout = 1000;	// 1 second
		$.ajax(
			{
				url: 'http://cstruter.localhost/tests/timers/results.php',
				cache: false
			}				
		).done(function(data) {
			$('#results').html(data);
			setTimeout(GetResults, timeout); // only call the function again once we're done
		}).fail(function(jqXHR, textStatus, errorThrown) {
			if (confirm("Error sending request, try again?")) {
				setTimeout(GetResults, timeout); // try call the function again	
			}
		});
	}
 
	GetResults();
 
</script>

You'll notice that we only set our delayed callback as soon as we had a succesful response back from our server, when something goes wrong with our response, we prompt the user to try again.

Note that like the setInterval function, we've got a function to stop our setTimeout as well - clearTimeout.

Now in the beginning of this post I mentioned that these functions are actually pseudo-threaded in that it runs on the same thread. To demonstrate the problem with this (from a threading perspective) you need to run the following snippet along with snippet 1.

Snippet 3
setInterval(
	function ()
	{	
		var j = 0;
		for (var i = 0; i < 1000000000; i++) { j++; } // simulate some intensive work
	}, 1000);


You will notice that now instead of getting a nice smooth time ticker, the ticker starts to lag behind a bit, skipping seconds. Which is obviously not the ideal behavior we're looking for but obvious seeing that we're doing everything on one thread.

Wouldn't it be nice if we could put the problem function in its own isolated thread? Leaving the UI thread open for all things UI?

In the next part we're going to have a look at doing exactly that using web workers.




Post/View comments
 
1 2 3 4 5 6 7 8 9 10 Last / 65 Pages (129 Entries)

Latest Posts

MS SQL: Parameter Sniffing


2012-05-21 22:38:48

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21