Frontend Labs
⋯

38. Web Workers: postMessage, structured clone, transferable objects

A dedicated Worker runs a separate script on its own OS thread, with its own global scope (self, not window) — no DOM access, but full access to fetch, timers, and (crucially) heavy computation that would otherwise freeze the UI.

// main.js
const worker = new Worker("worker.js");
worker.postMessage({ cmd: "compute", n: 40 });
worker.onmessage = (e) => console.log("fibonacci result:", e.data.result);
worker.onerror = (e) => console.error("worker crashed:", e.message);

// worker.js
self.onmessage = (e) => {
  if (e.data.cmd === "compute") {
    const result = fib(e.data.n);          // blocks the WORKER thread, not the main thread
    self.postMessage({ result });
  }
};
function fib(n) { return n <= 1 ? n : fib(n - 1) + fib(n - 2); }

Data passed via postMessage is copied, not shared, using the structured clone algorithm — which handles objects, arrays, Map/Set, Date, and typed arrays, but NOT functions, DOM nodes, or class instances with methods/prototypes (only their plain-data shape survives).

worker.postMessage({ date: new Date(), items: new Map([["a", 1]]) }); // fine, structured-clonable
worker.postMessage({ fn: () => {} });   // throws DataCloneError — functions aren't clonable

Transferable objects avoid the copy entirely for large binary data — ownership of the underlying memory moves to the receiver, and the sender's reference becomes unusable (zero-copy, not "clone-then-delete"):

const buffer = new ArrayBuffer(64 * 1024 * 1024);  // 64MB
worker.postMessage({ buffer }, [buffer]);           // second arg: list of transferables
buffer.byteLength;   // 0 — the sender no longer owns this memory at all

Generated from real-life-JS-guide.md · 8 Oct 2026 16:36