Categories
JavaScript

Introduction to Shared Workers

Spread the love

Shared workers are special web workers that can be accessed by multiple browser contexts like browser tabs, windows, iframes, or other workers, etc.

They’re different from dedicated workers in that they are instances of SharedWorkers and have a different global scope.

All browser contexts must be within the same domain in accordance with the same-origin policy.

In this article, we’ll look at the characteristics of shared and workers and how to create one.

Characteristics of Shared Workers

The difference between dedicated and shared workers is that dedicated workers can only be accessed by one script. Shared workers can be accessed by multiple scripts even if each page run inside different windows.

This enables more flexible communication between multiple scripts.

The scripts that access the workers can do so by accessing it through the MessagePort object created using the SharedWorker.port property. If the onmessage event is attached using addEventListener , then the port is manually started using the start method.

When the port is started multiple scripts can post messages to the worker and handle messages sent using the port.postMessage and port.onmessage respectively.

Other than that, scripts still communicate with the shared worker by communication messages to the worker and get messages back from the worker via scripts.

The SharedWorker constructor also takes an option object with the following options:

  • type : a string specifying the type of worker to create. The value can be classic or module and defaults to classic .
  • credentials : a string specifying the type of credentials to use for the worker. The value can be omit (no credentials required), same-origin or include . If it’s not specified, the type is class then omit is the default.
  • name : a string specifying the identifying name for the SharedWorkerGlobalScope representing the scope of the worker. It’s mainly used for debugging.

The constructor will throw a SecurityError if it’s not allowed to start workers, like if the URL is invalid or same-origin policy is violated.

NetworkError is raised if the MIME type of the worker script is incorrect.

SyntaxError is raised is the worker’s URL can’t be parsed.

Creating and Using a Shared Worker

We can create a shared worker and use it without too much hassle. First, we have to create a shared worker. Then we have to create the scripts to use it. Finally, we add the HTML so that we can do something with it.

Start by creating a scripts folder and add a sharedWorker.js file:

onconnect = (ev) => {  
  const [port] = ev.ports; 
  port.onmessage = e => {  
    const [first, second] = e.data;  
    let sum = +first + +second;  
    if (isNaN(sum)) {  
      port.postMessage("Both inputs should be numbers");  
    }  
    else {  
      const workerResult = `Result: ${sum} `;  
      port.postMessage(workerResult);  
    }  
  };  
};

In the code above, we have an onconnect handler assigned to the onconnect property. Then inside the handler function, we get the port that the shared worker uses to communicate with other scripts.

Next, we assign an event handler to the onmesaage property of the port that we got from the parameter of the onconnect handler. Then we can get the data from the parameter of the onmessage handler to and compute the sum.

Inside the handler, we check if both pieces of data sent from the external scripts are numbers and then add the numbers together if they’re and send them to the scripts.

We have to call port.start(); inside the onconnect event handler at the end if we want to use addEventListener to add a listener to the message event instead of assigning an event handler to onmessage .

Other we send a message back to the external scripts indicating that one or not pieces of data sent aren’t a number.

Then we create a main.js and main2.js in the script.js and add:

const sharedWorker = new SharedWorker("scripts/sharedWorker.js");  
const first = document.getElementById("number1");  
const second = document.getElementById("number2");  
const result = document.getElementById("result");  
sharedWorker.port.start();  
first.onkeyup = () => {  
  sharedWorker.port.postMessage([first.value, second.value]);  
};

second.onkeyup = () => {  
  sharedWorker.port.postMessage([first.value, second.value]);  
};

sharedWorker.port.onmessage = e => {  
  result.textContent = e.data;  
};

We get the input from the HTML file which we’ll create and then send it to our shared worker. We have to use the port of the shared worker to do this as we do by using sharedWorker.port.postMessage .

In:

sharedWorker.port.onmessage = e => {  
  result.textContent = e.data;  
};

We get back the data sent from the shared worker.

Both main.js and main2.js do the same thing but they’re used by different pages.

Finally, create index.html and index2.html and add:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Add Worker</title>  
  </head>  
  <body>  
    <form>  
      <div>  
        <label for="number1">First Number</label>  
        <input type="text" id="number1" value="0" />  
      </div>  
      <div>  
        <label for="number2">Second Number</label>  
        <input type="text" id="number2" value="0" />  
      </div>  
    </form>  
    <p id="result">Result</p>  
    <script src="scripts/main.js"></script>  
  </body>  
</html>

In the end, we get:

https://thewebdev.info/wp-content/uploads/2020/04/shared-worker.png

When we go to index.html or index2.html . We should be able to do calculations on both pages without them interfering with each other.

Creating a shared worker isn’t too different from creating and dedicated worker. The constructor arguments are exactly the same. The only difference is that we can use it with more than one script and we need to get the port object to communicate between external scripts and shared workers.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *