Skip to main content

What does postMessage() do between threads?

What postMessage() does

postMessage() is a method that lets you send a message from one context to another (for example, from the main thread to a Web Worker or vice versa).

It does not perform direct memory access, but passes a copy of the data, asynchronously, through the message passing mechanism.

What this looks like with a Web Worker

Example

javascript
// main.js const worker = new Worker('worker.js'); // Send a message to the worker worker.postMessage({ task: 'sum', a: 5, b: 7 }); // Get the response worker.onmessage = (event) => { console.log('Response from the worker:', event.data); };
javascript
// worker.js onmessage = (event) => { const { task, a, b } = event.data; if (task === 'sum') { postMessage(a + b); // send the result back } };

What happens:

  1. The main thread calls worker.postMessage(...);
  2. The message is serialized and placed into the worker's message queue;
  3. The onmessage event fires in the worker;
  4. The worker processes it and replies via postMessage();
  5. The main thread catches that event via onmessage.

All of this happens asynchronously; JavaScript does not wait for the worker to respond.

What exactly gets passed

You can pass:

  • Primitives (string, number, boolean, null, undefined);
  • Objects (JSON-compatible);
  • ArrayBuffer, Blob, File, ImageBitmap;
  • Transferable objects - passed without copying.

What Transferable Objects are

Normally data is copied when passed between threads (via structured clone). But for large binary data this is expensive.

Transferable objects (for example, ArrayBuffer) can be "passed by reference"

  • without copying, just by transferring ownership.

Example:

javascript
const buffer = new ArrayBuffer(1024); worker.postMessage(buffer, [buffer]); // pass it as transferable

After transfer, buffer becomes invalid in the main thread (because "ownership" has moved to the worker). This is 10-100 times faster when transferring large data.

What postMessage() returns

Nothing. It simply queues a message on the other side. The receiver catches it through the message event:

javascript
worker.onmessage = (event) => { console.log(event.data); };

Communication in both directions

FromMethodListener
Main thread -> workerworker.postMessage()onmessage in the worker
Worker -> main threadpostMessage()worker.onmessage

An "echo" example (echo worker)

javascript
// worker.js onmessage = (event) => { postMessage(`Echo: ${event.data}`); };
javascript
// main.js worker.postMessage('Hello!'); worker.onmessage = (e) => console.log(e.data); // -> "Echo: Hello!"

postMessage() is not only for Web Workers

This method is universal; it works across different browser contexts:

Where it is usedExample
window -> iframeiframe.contentWindow.postMessage(data, origin)
iframe -> parentwindow.parent.postMessage(data, origin)
between tabsotherWindow.postMessage(data, origin)
Service Worker <-> Mainnavigator.serviceWorker.controller.postMessage(data)
Web Worker <-> Mainworker.postMessage(data)

Example: window.postMessage() between pages

javascript
// Page A const popup = window.open('https://example.com/popup.html'); popup.postMessage('Hi, page B!', 'https://example.com'); // Page B window.addEventListener('message', (event) => { if (event.origin === 'https://example.com') { console.log('Message received:', event.data); } });

Very useful for safe communication between different domains (CORS-safe).

How it works under the hood

  1. When postMessage() is called, the data is serialized using the Structured Clone Algorithm;
  2. A copy of the data is placed into the receiver's queue;
  3. When the thread frees up, the browser calls the onmessage(event) handler;
  4. The data is available in event.data.

What is inside event

javascript
onmessage = (event) => { console.log(event.data); // the data itself console.log(event.origin); // the source (for windows/iframes) console.log(event.ports); // MessagePort, if any console.log(event.source); // who sent the message };

A simple analogy

Think of postMessage() as a postal service between offices.

Each office (a JS thread) works in isolation. When one wants to pass data to another, it drops a letter (a message) into a mailbox (postMessage).

The other office picks up the letter when it has time (onmessage).

Summary

What it doesExplanation
postMessage()Sends a message between threads / contexts
Works asynchronouslyDoes not block the code
Passes data by copyThrough structured clone
OptimizationTransferable objects - without copying
Two-way communicationBoth threads can send and receive
Used whereWeb Workers, iframes, windows, Service Workers

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.