Wednesday, April 16, 2014

Multithreading in Javascript using Web Workers

In the past JavaScript use to be single-threaded, meaning multiple scripts cannot run at the same time due to which UI can block many times.
To overcome this problem now Web Workers have been introduced. Web Workers run in an isolated thread.

There are two types of web worker.
1. Dedicated web worker
2. Shared web worker

What is the difference between the two

Dedicated Workers are linked with the script that created them but Shared workers are created so that any script running in the same origin can communicate with them, either by the URL of the script used to create it, or by name.

How to spawn a dedicated worker and communicate with it.

var dedicatedWorker = new Worker('task.js');

The task.js file is now async loaded and the new dedicated worker is available.
In case of task.js file is not present, the worker will fail silently.

After the spawning of the worker thread we can start worker by using postMessage()

dedicatedWorker.postMessage();

postMessage method can accept a string or JSON depending upon the browser support.
We communicate between worker and its parent page through message passing.
We define a listener in the worker as well in the parent page so that both can communicate with each other by passing messages.

Parent page

var dedicatedWorker = new Worker('task.js');
dedicatedWorker.addEventListener('message', function(e) {
console.log('Message replied by Worker : ', e.data);
}, false);
dedicatedWorker.postMessage("Hi Worker");

task.js

self.addEventListener('message', function(e) {
console.log("Message received by Worker : " + e.data);
self.postMessage("Hi Master");
}, false);

Console
Message received by Worker : Hi Worker
Message replied by Worker : Hi Master</code>

We can terminate a web worker by calling the terminate method

dedicatedWorker.terminate();

How to spawn a shared worker and communicate with it.

page 1


var sharedWorker = new SharedWorker('task.js');
sharedWorker.port.addEventListener("message", function(e) {
console.log('Page 1 received message: '+ e.data);
}
}, false);
sharedWorker.port.start();
// post a message to the shared web worker
sharedWorker.port.postMessage("Master 1");

page 2

var sharedWorker = new SharedWorker('task.js');
sharedWorker.port.addEventListener("message", function(e) {
console.log('Page 2 received message: '+ e.data);
}
}, false);
sharedWorker.port.start();
// post a message to the shared web worker
sharedWorker.port.postMessage("Master 2");

task.js

var ports = [] ;
self.addEventListener("connect", function (e) {
var port = e.ports[0];
ports.push(port);
port.start();
port.addEventListener("message",function(e) {
port.postMessage("Reply from SharedWorker to: " + e.data + ". Total number of connections : " + ports.length)
});
}, false);

When the page 1 loads it starts the shared web worker.In console the output is

Reply from SharedWorker to: Master 1. Total number of connections : 1

When the page 2 loads the console would be

Reply from SharedWorker to: Master 2. Total number of connections : 2

Features Available to Workers

Web workers only have access to a subset of JavaScript's features:
  The navigator object
  The location object (read-only)
  XMLHttpRequest
  setTimeout()/clearTimeout() and setInterval()/clearInterval()
  The Application Cache
  Importing external scripts using the importScripts() method
  Spawning other web workers

Workers do NOT have access to:

  The DOM (it's not thread-safe)
  The window object
  The document object
  The parent object

No comments:

Post a Comment