Lesson 0005 · ~12 minutes
One skill: decide when multi-context work needs a
SharedWorker versus a dedicated worker,
BroadcastChannel, or a service worker.
You can defend “shared worker yes / no” when the product story is multi-tab coordination — without treating every tab problem as a worker problem.
A
SharedWorker
is a worker that
multiple browsing contexts (tabs, windows, iframes) of
the same origin can connect to. MDN:
once created, any same-origin script can obtain a reference and talk to
it; it stays alive while something holds a reference.
Dedicated worker mental model: one owner page, offload my CPU. Shared worker mental model: one long-lived coordinator process that several UIs attach to.
Same isolation rules: no DOM, message-passing (clone/transfer), capability list from lesson 4. You gain a shared JS realm across tabs — not free shared DOM or free shared React state.
From
MDN Using Web Workers: communication is via an explicit
MessagePort on worker.port. Inside the worker,
clients arrive on connect.
// each tab
const sw = new SharedWorker("shared.js");
sw.port.onmessage = (e) => console.log("from hub", e.data);
sw.port.postMessage({ type: "join", tabId: crypto.randomUUID() });
// shared.js
const ports = new Set();
onconnect = (e) => {
const port = e.ports[0];
ports.add(port);
port.onmessage = (ev) => {
// example: fan-out to every connected tab
for (const p of ports) {
p.postMessage({ type: "broadcast", payload: ev.data });
}
};
};
addEventListener("message", …) requires
port.start(); the onmessage setter starts
the port for you.
extendedLifetime can keep the worker briefly after last
disconnect for cleanup (analytics, flush to IDB) — see MDN lifetime
notes.
One page needs CPU offload. No shared process across tabs (each tab can spawn its own).
Same-origin tabs need pub/sub messages only — no shared memory, no single coordinator process. Lightest option for “tell other tabs X happened.”
You need one in-memory coordinator: single WebSocket to a server, shared cache of derived state, election of a leader tab’s work, multi-window map editor (spec multiviewer pattern).
Network proxy, offline, push — different lifecycle and job (lesson 1/4).
If tabs only need to notify each other, start with
BroadcastChannel (or storage events as a last resort). If
they need a shared process that holds state or owns a scarce
resource (one socket, one heavy engine), design a SharedWorker. If only
one tab exists and the issue is jank, dedicated worker.
| Risk | Why it bites |
|---|---|
| Cross-origin tabs | SharedWorker requires exact same origin — not “same site” loosely. |
| Browser support / mobile quirks | Historically rockier than dedicated workers; verify target browsers (MDN compat). Have a fallback story. |
| No fan-out built-in | You manage ports. Forgetting to track disconnects leaks or ghosts messages. |
| Debugging opacity |
Not the same DevTools surface as a page — use browser worker
inspectors (chrome://inspect/#workers, etc.).
|
| Overkill | “Sync logout across tabs” rarely needs a shared process — BroadcastChannel + clear storage often enough. |
Equal-length options. Product design reviews.
Trading dashboard: up to 8 tabs open; product wants one WebSocket to the market feed, all tabs update.
When the user logs out in one tab, other same-origin tabs should clear session UI within a second.
Photo editor: one tab, multi-second image filter freezes the UI. No multi-window requirement.
App shell on app.example.com and widget iframe on
cdn.example.com must share one in-memory session bus.
MDN — SharedWorker plus the shared-worker section of Using Web Workers. Optional contrast: BroadcastChannel.