Skip to main content

SharedWorker in JavaScript

A SharedWorker is a JavaScript thread that several contexts (tabs, windows, iframes) can use at the same time, as long as they are loaded from the same origin (protocol plus host plus port). Unlike a regular Worker, which dies when its tab is closed, a SharedWorker stays alive while at least one window is still connected.

Theory

TL;DR

  • One thread serves every tab and iframe of a single origin.
  • It is created with new SharedWorker('shared-worker.js'), and the channel is shared.port.
  • Every new connection arrives in the worker as an onconnect event carrying its own MessagePort.
  • The port has to be activated with port.start() if you subscribe with addEventListener instead of onmessage.
  • It lives while at least one client is connected, then the browser shuts it down.
  • There is no DOM access, and data is passed as a copy through structured clone.

Quick example

The code in shared-worker.js:

javascript
// shared-worker.js onconnect = (event) => { const port = event.ports[0]; console.log('New connection'); port.postMessage('Hello, tab!'); port.onmessage = (e) => { console.log('Message from a tab:', e.data); // send a reply back port.postMessage(`Received: ${e.data}`); }; };

The code on every tab (main.js):

javascript
// main.js const shared = new SharedWorker('shared-worker.js'); const port = shared.port; // activate the channel port.start(); // listen for replies from the worker port.onmessage = (e) => { console.log('SharedWorker reply:', e.data); }; // send a message to the worker port.postMessage('Hello from a tab!');

What happens:

  • all tabs connect to one and the same worker;
  • each of them receives messages through its own port;
  • the worker can coordinate them, for example broadcasting shared data to everyone.

How SharedWorker differs from a regular Worker

FeatureWorker (Dedicated)SharedWorker
Used byOne pageSeveral tabs and windows
Created withnew Worker('worker.js')new SharedWorker('worker.js')
Communication channelpostMessage directlyThrough a port object
LifetimeWhile the tab is openWhile at least one context is connected
Reachable from other tabsNoYes, on the same origin

The interaction diagram:

text
[ Tab 1 ] [ Tab 2 ] [ Iframe ] | | | +--------> [ SharedWorker Thread ] <+ ^ | | (ports[]) v business logic

Every tab connects to one worker thread, and the worker exchanges messages with each tab through that tab's port.

How onconnect and MessagePort work

When a new tab calls new SharedWorker(), the browser does not spawn a new thread if the worker already exists. It simply fires the onconnect event and passes in a MessagePort object, which is the communication channel.

That way a single SharedWorker can manage dozens of ports, meaning dozens of tabs.

Broadcasting to every tab

javascript
// shared-worker.js const ports = []; onconnect = (e) => { const port = e.ports[0]; ports.push(port); port.start(); port.onmessage = (event) => { // broadcast the message to every connected tab for (const p of ports) { p.postMessage(`From a tab: ${event.data}`); } }; };

Now, if you open two tabs:

  • tab 1 sends port.postMessage("Hi"),
  • both tabs receive "From a tab: Hi".

That is already a real chat between tabs.

Where it is useful

ScenarioWhy SharedWorker helps
Shared chat between tabsmessages can be synchronised
Background data processingone tab computes, everyone gets the result
A shared WebSocket subscriptionone connection for all tabs, saving resources
Shared cache and IndexedDB logica single background for all of them
State synchronisationfor example a shared auth token across tabs

What to keep in mind

  • SharedWorker works only within one origin (https://example.com is not the same as http://example.com).
  • It is not a Service Worker; the worker types are different and not interchangeable.
  • Support is incomplete: some older browsers and Safari on iOS do not have it.
  • Communication goes through port.postMessage() and port.onmessage.

Security and data transfer

  • Workers are isolated: no access to the DOM, window or document.
  • Data is passed by copy (structured clone).
  • For fast exchange of large binary payloads you can use Transferable objects (ArrayBuffer).

A simple analogy:

Imagine a SharedWorker is the office server in a company. Every employee (a tab) can connect to it. The server keeps the shared data and pushes updates to everyone. While at least one employee is working, the server stays up. When everyone closes their tabs, the server shuts down automatically.

Summary:

FeatureDescription
What it doesLets several pages of one site share a JS thread
Main advantageShared logic and data across tabs
CommunicationThrough a MessagePort (port.postMessage / port.onmessage)
LifecycleWhile at least one client is open
No DOM accessMessages only
Typical scenariosShared WebSocket, cache, state sync, cross tab chat

Common mistakes

  • Forgetting port.start(). If you subscribe with port.addEventListener('message', ...), the port stays inactive and no messages arrive. Assigning port.onmessage starts the port implicitly.
  • Calling shared.postMessage(...) instead of shared.port.postMessage(...). In a SharedWorker the method lives on the port, not on the worker object itself.
  • Expecting a SharedWorker to see a tab from a different origin or a different script path. A worker is identified by origin plus script URL, otherwise it is a different worker.
  • Not removing closed ports from the ports list. Ports of dead tabs pile up and the broadcast starts writing into nowhere.
  • Confusing SharedWorker with Service Worker. The first is a shared computation thread, the second is a network proxy with its own lifecycle.
  • Relying on SharedWorker as the only way to sync tabs. Because support is uneven, keep a fallback such as BroadcastChannel.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.