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.
Interview question
When you transfer an ArrayBuffer via postMessage, what happens to the sender's original buffer?
- a.It is deep-copied, leaving the sender's original intact
- b.It remains valid until the worker finishes processing
- c.It shares memory with the receiver like a SharedArrayBuffer
- d.It is destroyed and becomes unusable in the sender threadCorrect
Why? this is the answer
Transferring moves ownership of the ArrayBuffer to the receiver and destroys the sender's copy. Deep-copying describes default postMessage behavior without transfer, while shared memory describes SharedArrayBuffer.
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
- #web workers
- #postmessage
- #structured clone
- #transferable objects
- #javascript
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.
See open roles