Lesson 0004 · ~12 minutes

Deal-breakers: when clone (or transfer) is the wrong move

One skill: run a 60-second risk scan — reject the wrong copy tool before it ships, including the orphan transfer list.

Win for this lesson

In a design review you can kill “clone the Vue store,” “transfer a leftover buffer,” “JSON as a deep clone,” and “clone then postMessage for no reason.”

1. The miss: the list does not send

Scenario C: structuredClone({ n: 1 }, { transfer: [orphan] }). MDN is blunt: the transfer array only says how certain resources should be sent. It does not send them. They still detach.

Same rule on postMessage(value, transfer). If the buffer is not reachable from value, you get a hole on one side and a detached corpse on the other. Put the buffer in the object and in the list.

2. Risk scan (six that show up in reviews)

Smell What actually happens Do instead
Vue / Pinia / MobX object in the payload Proxy is an exotic object → DataCloneError (spec) Clone a plain DTO. In Vue 3, toRaw only unwraps one layer — prefer a data snapshot you control
Class instance / “smart” model Flatten — methods and privates gone DTO now; custom serializer if you need revival
structuredClone then postMessage / IDB / pushState You paid for two clones Let the implicit API clone, unless you need a snapshot for another reason
Full state every frame / huge graph Serialize blocks the sender (Surma) Patches, chunking, or transfer — not more clones
REST / file “via structuredClone” Still a JS value, not text JSON.stringify (and accept Date/Map loss)
Orphan in the transfer list Source detaches; clone never sees it Buffer must be in the value and the list
Loud vs silent

Clone throws on functions, DOM, proxies. JSON drops functions and turns Dates into strings. Picking the wrong algorithm hides the bug or explodes a worker. Know which one you are on.

3. Green-light when…

Printable version: integration checklist.

4. Practice — kill the bad proposal

Equal-length options. C comes back as snippet A.

Snippet A · lesson 3 C

structuredClone({ n: 1 }, { transfer: [orphan] })orphan is an ArrayBuffer not on the object.

Snippet B

A Vue 3 reactive store object is passed to structuredClone to snapshot a form.

Snippet C

You will worker.postMessage({ type, draft }). The main thread will keep using draft after the send.

Snippet D

A worker gets the entire 2MB editor document on every keystroke. The UI janks on send.

Snippet E

Persist a domain Invoice (methods, private fields, schema version) to a file other services read for years.

5. What to remember

Ask your teacher A DataCloneError from a store, an Immer draft, or a “buffer is detached” you cannot find — ask. Those are this lesson in production.

Primary source (read next)

Re-read the two paragraphs on MDN — Transferable objects that say transferred resources must be attached to the data object. Then skim the checklist. Next lesson is the decision playbook.