Suggest an editImprove this articleRefine the answer for “SharedWorker in JavaScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**A `SharedWorker` is a JavaScript thread used at the same time by several contexts of the same origin: tabs, windows and iframes.** Unlike a regular `Worker`, which dies with its tab, a SharedWorker stays alive as long as at least one client is connected. Communication does not go directly but through a `MessagePort`: the page takes `shared.port`, calls `port.start()` and talks through `port.postMessage()` / `port.onmessage`, while inside the worker every new connection arrives in the `onconnect` event with its own port. That lets one worker hold a shared WebSocket, a shared cache or auth state for every tab and broadcast updates to all of them. ```javascript const shared = new SharedWorker('shared-worker.js'); shared.port.start(); shared.port.postMessage('Hello from a tab!'); ``` **Key point:** one thread for all tabs of an origin, communication through ports, alive while at least one client is connected, and still no DOM access.Shown above the full answer for quick recall.Answer (EN)Image**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 | Feature | `Worker` (Dedicated) | `SharedWorker` | | --- | --- | --- | | Used by | One page | Several tabs and windows | | Created with | `new Worker('worker.js')` | `new SharedWorker('worker.js')` | | Communication channel | `postMessage` directly | Through a `port` object | | Lifetime | While the tab is open | While at least one context is connected | | Reachable from other tabs | No | Yes, 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 | Scenario | Why SharedWorker helps | | --- | --- | | **Shared chat between tabs** | messages can be synchronised | | **Background data processing** | one tab computes, everyone gets the result | | **A shared WebSocket subscription** | one connection for all tabs, saving resources | | **Shared cache and IndexedDB logic** | a single background for all of them | | **State synchronisation** | for 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: | Feature | Description | | --- | --- | | **What it does** | Lets several pages of one site share a JS thread | | **Main advantage** | Shared logic and data across tabs | | **Communication** | Through a `MessagePort` (`port.postMessage` / `port.onmessage`) | | **Lifecycle** | While at least one client is open | | **No DOM access** | Messages only | | **Typical scenarios** | Shared 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`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.