JavaScript has always been a language which is more widely used but very less
documented or updated. But with Web Workers, developers can build more
responsive and highly interactive browser based applications in JavaScript.
Workers add the power of threading in JavaScript which is undoubtedly a big boon
to browser applications. Workers provide a way through which a script can be run
in background process. An analogy can be a thread of a process, in which the
main process gets divided into small threads. Web workers were introduced in
Firefox 3.5's JavaScript engine. It allows you to have multiple threads in
JavaScript wherein you can perform various tasks without having to interrupt the
user browsing the webpage. Workers can perform the following task; perform any
JavaScript tasks without interrupting user interface, perform I/O using
XMLHttpRequest (however, the responseXML and channel attributes are always null)
, can create sub-workers as long as those workers are hosted within the same
origin as the parent page (sub-workers URIs are relative to the parent worker
location) and can use timeouts and intervals.
While workers can perform the above tasks very flawlessly, one thing which it
can't do is manipulating DOM directly. That means for making changes to the DOM,
the worker has to return message to its creator process which in turn will
perform the required changes. This is so very true for any background thread(s)
in general programming scenario.
Direct Hit! |
Applies To: Developers Primary Link: |
Thread Safety
When we talk about creating separate threads in the process, then comes the
problem of thread concurrency. Worker interface spawns OS-level threads, which
mean we have to be careful while writing code with workers. However in case of
“Web workers” in Firefox these problems have been taken care of, so that it is
really hard to cause such concurrency problem. A clear example to this can be
that there is no direct access to non-thread safe components like DOM.
Web Worker event and methods
Events
onmessage: this event will be raised when a message is posted from or to
the worker.
onerror: this event will be raised when an error occurred in the
worker.
Methods
postMessage: this method is used to send a message from or to the worker.
terminate: kills the worker immediately without waiting it to finish
its task. close: similar to terminate method but is used from within the worker
itself.
Spawning a worker
It is straight forward to use a worker. All we need to do is call the
Worker() constructor which takes a string parameter of the URI of the script to
be executed. By setting the onmessage property with a appropriate function we
can receive the message from the worker. Here is a simple example on how to
spawn a worker:
var myWorker = new
Worker('my_worker.js');
myWorker.onmessage = function(event)
{
alert("Called back by the
worker!\n");
};
Terminating a worker
Terminating or killing a worker is again very simple. By calling worker's
method terminate() the running worker will stop immediately without finishing
its current operation. However if you want to kill a worker from within, then
you need to use close() method instead of terminate(). Here is a a simple
example on how to terminate a worker.
myWorker.terminate();
Error Handling
A script without error handling is considered incomplete; hence we need to
have error handling in workers as well. When an error is encountered at runtime,
onerror event handler is called. It receives an event called error which helps
in controlling the current error. If the worker calls the preventDefault()
method , it prevents the default action to take place.
Ideal scenario to use workers
As discussed above workers are the threads which work in the background. So
the scripts which are more processor intensive should use workers to speed-up
the overall web page. For eg. If a script requires long and intense calculation
on a page while the other script wants to perform some network input-output, in
that case as long as the calculation is taking process, the network process is
put on hold. But using workers both can be done at the same time.
Example
The following JavaScript code is the worker file, which is saved in the same
directory as of parent file. We keep the name of the file as my-worker.js
function calculate_fact(n)
{
var result = 1;
for (i = 1; i <= n; i++)
result *= i;
return result;
}
//message sent to the worker
onmessage = function(event)
{
var n = parseInt(event.data);
var fact = calculate_fact(n);
//send it back
postMessage(fact);
return;
}
The onmessage function is called when the HTML calls
postMessage() on the worker.
Example
value="Calc Factorial" onclick="calc_fact();" />
value="Terminate Worker" onclick="terminate_worker();" />
var worker = new Worker("my-worker.js");
//message from worker
worker.onmessage = function(event)
{
document.getElementById("result").textContent = event.data;
}
//error handler
worker.onerror = function(error)
{
alert("ERROR: " + error.message + "\n");
}
function calc_fact()
{
var n = document.getElementById("num").value;
//Spawn the worker
worker.postMessage(n);
}
function terminate_worker()
{
worker.terminate(); //kill the worker
}
After spawning the worker, the onmessage handler is
configured to display the results by setting the contents of the label element,
and the onerror handler is set to dump the error message, if any. The worker can
be terminated at any point of time by called the terminate_worker() method which
gets called when user clicks on the second button with label “Terminate Worker”.
Sachin Khosla, Founder, Digimantra