Reference

Messaging, clone & transfer

The channel tax between main thread and workers. Normative base: WHATWG structured data.

Default: structured clone (copy)

worker.postMessage(value);
// value is serialized then deserialized on the other side
// each realm gets its own copy — not the same object

Transfer: move ownership (zero-copy for buffers)

// Transfer the underlying ArrayBuffer — sender loses it
worker.postMessage(u8, [u8.buffer]);
// after this, u8.byteLength === 0 on the sender (detached)

Cost rules of thumb (Surma, measure in your app)

Rough payload Design take
≤ ~10 KiB Low risk even near frame budget; fine for frequent UI updates
≤ ~100 KiB Usually OK for interaction budget (~100ms) even on slow devices
≫ 100 KiB or high frequency Design for patches, chunking, or transfer — don’t clone whole state every tick

Source framing: Is postMessage slow? — rules of thumb, not laws. Serialize blocks sender; deserialize blocks receiver.

Architecture escapes when clone hurts

  1. Patches — send diffs, not full state (Immer-style patchsets).
  2. Chunking — stream partial results so UI can paint.
  3. Transfer — move large binary with ArrayBuffer ownership.
  4. SharedArrayBuffer — true shared memory + Atomics; COOP/COEP isolation required in modern browsers; advanced / later.