Worker postMessage: The Structured Clone Pipe

Worker postMessage moves data between threads via structured cloning. Use it to offload heavy work without blocking the UI. The message argument is mandatory, so omitting it is an error and you must pass null when there is no data.
WHY IT EXISTS: The browser runs JavaScript on a single main thread that handles rendering, user input, and script execution. If you perform expensive work like image processing, large JSON parsing, or complex math on that thread, frames drop and the UI freezes. Web Workers were created to run scripts in background threads, but a thread is useless without a way to get data in and out safely. postMessage is that mechanism. It was designed to move data across an isolation boundary without shared memory by default, keeping concurrency simple and avoiding race conditions.
THE MENTAL MODEL: Think of a worker as a separate process and postMessage as an internal mail courier. You hand the courier a package, any JavaScript object that can survive a structured clone. The courier delivers it to the other side and drops it in an inbox. The recipient opens the package via an onmessage handler. If you want to send a large parcel like an ArrayBuffer and you no longer need the original, you can tell the courier to transfer it, meaning the sender copy is destroyed upon delivery.
HOW IT WORKS: You call worker.postMessage from the main thread, or self.postMessage from inside the worker. The message argument is mandatory and can be any value supported by the structured clone algorithm, including objects with cyclical references. Only one top-level object is sent per call, so multiple values are typically wrapped in an array. The optional transfer array lists Transferable objects such as ArrayBuffers or MessagePorts whose ownership moves to the receiver; after transfer, the sender cannot use them. Behind the scenes, the Worker delegates to a MessagePort, which schedules a task on the receiver event loop, so message handling is asynchronous and non-blocking.
WHEN TO USE IT: Use postMessage when you need to offload CPU-intensive tasks, process large datasets, or run long algorithms without dropping frames. It is also useful when you need true isolation for third-party code or when you want to take advantage of multiple CPU cores. Transferable objects are ideal when you are moving large binary data and want to avoid copying overhead.
WHEN NOT TO USE IT: Do not use postMessage for high-frequency, low-latency communication like real-time audio or game loops where microsecond delays matter, because every message schedules a new event loop task. Avoid it when you need shared mutable state; instead, consider SharedArrayBuffer for that niche. Also do not send functions or DOM nodes, because the structured clone algorithm cannot serialize them.
ONE CANONICAL EXAMPLE: In a main script you create a worker with new Worker and a script URL. You then listen for input changes on two form fields and post their values as an array: myWorker.postMessage([first.value, second.value]). Inside the worker script, you listen with onmessage, perform a calculation, and post the result back with self.postMessage(result). If you need to move a large ArrayBuffer without copying, you create it in main, post it with myWorker.postMessage(buffer, [buffer]), and after the call the original buffer in main is detached and unusable.
Source: developer.mozilla.org
Read the original → developer.mozilla.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.