How to call shared worker from the web worker?

3.3k views Asked by At

Is it possible to call a Shared Worker from the Web Worker?

Could you please give me an example.

In my case I have a few web workers and I need to share a singleton service between them.

2

There are 2 answers

2
levi On BEST ANSWER

The SharedWorker constructor is not currently available within the WorkerGlobalScope, so you will not be able to construct an instance like you would in an iframe or window.

What you can do is, create a MessageChannel for each of your workers, and use it to communicate between the worker and sharedWorker. Though doing this would negate the need for an actual SharedWorker, since you could just as well use a single Worker instead.

Example:

var numWorkers = 4;
var sharedWorker = new Worker("worker-shared.js");

for(var i = 0; i < numWorkers; i++) {
  var dedicatedWorker = new Worker("worker-dedicated.js");
  var channel = new MessageChannel();
  dedicatedWorker.postMessage({sharedWorkerPort: channel.port1}, [channel.port1]);
  sharedWorker.postMessage({workerPort: channel.port2}, [channel.port2]);
}

Demo

1
Michal Charemza On

You can use a technique similar to that at https://stackoverflow.com/a/30796101/1319998 . For each dedicated worker, you can create a shared worker object, pointing to the same script, and pass its port to the dedicated worker.

Note that for the same script URL, new SharedWorker(scriptUrl) doesn't necessarily create a new shared worker thread: it just creates a new object that allows you to communicate with the shared worker thread, and only creates the thread itself if it doesn't already exist.

As an example, the following creates 2 Worker objects, that each create a separate dedicated worker thread, and 2 SharedWorker objects, that in total creates one shared worker thread. The port objects of the shared workers are passed to the dedicated workers:

var sharedWorkerA = new SharedWorker("worker-shared.js");
sharedWorkerA.port.start();

var dedicatedWorkerA = new Worker("worker-dedicated.js");
dedicatedWorkerA.postMessage({sharedWorkerPort: sharedWorkerA.port, workerName: 'A'}, [sharedWorkerA.port]);

var sharedWorkerB = new SharedWorker("worker-shared.js");
sharedWorkerB.port.start();

var dedicatedWorkerB = new Worker("worker-dedicated.js");
dedicatedWorkerB.postMessage({sharedWorkerPort: sharedWorkerB.port, workerName: 'B'}, [sharedWorkerB.port]);

The dedicated workers can then post messages on the port objects they have received:

self.onmessage = function(e) {
  var workerName = e.data.workerName;
  var sharedWorkerPort = e.data.sharedWorkerPort;

  self.setInterval(function() {
    sharedWorkerPort.postMessage('sent from dedicated worker ' + workerName);
  }, 2000);
};

And the the shared worker can receive them:

var num = 0;
self.onconnect = function(e) {
  console.log('shared connect');
  var port = e.ports[0];

  port.onmessage = function(e) {
    num++;
    console.log('Received in shared worker: ', e.data);
    console.log('Number of messaged received:', num);
  };
};

I've put a bit of extra code in there just to show that there is indeed one actual shared worker thread running. You can see the above working at http://plnkr.co/edit/RcxxY2EDIcclUegC82wG?p=preview