Start · Sprachen · JavaScript · Referenz · WorkerGlobalScope.structuredClone()

WorkerGlobalScope.structuredClone()

Methode

Erstellt im Worker-Kontext mit dem Structured-Clone-Algorithmus eine tiefe Kopie eines Werts. Mit <code>transfer</code> lassen sich übertragbare Objekte verschieben.

seit JavaScript Baseline 2022: Chrome 98, Firefox 94, Safari 15.4, Kategorie: webapi

Signatur

WorkerGlobalScope.structuredClone(value, options)

Beschreibung

structuredClone() ist eine globale Funktion und steht in Web Workern, Shared Workern und Service Workern über self bzw. direkt als structuredClone() zur Verfügung. Sie verwendet denselben Structured-Clone-Algorithmus wie postMessage() und legt eine vollständig unabhängige, tiefe Kopie eines Werts an. Verschachtelte Objekte, Arrays, Map, Set, Date, RegExp, ArrayBuffer, typisierte Arrays, Blob, File, ImageData und viele weitere Typen werden dabei korrekt kopiert.

Anders als der verbreitete Trick JSON.parse(JSON.stringify(obj)) bleiben dabei zirkuläre Referenzen und mehrfach referenzierte Unterobjekte erhalten. Auch Datentypen wie Date, Map oder BigInt gehen nicht verloren. Das ist praktisch, wenn ein Worker empfangene Daten verändern will, ohne einen gemeinsamen Zustand anzutasten, oder wenn Zwischenstände (Snapshots) eines Berechnungszustands gespeichert werden sollen.

Mit der Option transfer werden übertragbare Objekte wie ArrayBuffer, MessagePort oder ImageBitmap nicht kopiert, sondern verschoben. Der Klon übernimmt den Speicher, und das Original wird unbrauchbar gemacht (detached). Bei großen Binärdaten spart das Speicher und Rechenzeit.

Parameter

Name Typ Default Beschreibung
$value Pflicht any Der zu klonende Wert. Das kann ein primitiver Wert oder ein beliebig verschachteltes, strukturiert klonbares Objekt sein.
$options { transfer?: Transferable[] } {} Optionales Objekt. transfer ist ein Array übertragbarer Objekte, die in den Klon verschoben statt kopiert werden.

Rückgabewert

Typ
any
Beschreibung
Eine tiefe Kopie von value. Wirft eine DOMException vom Typ DataCloneError, wenn ein Teil des Werts nicht klonbar ist.

Beispiele

Tiefe Kopie im Worker mit Date, Map und zirkulärer Referenz

// worker.js
const state = {
  created: new Date('2024-01-01T00:00:00Z'),
  cache: new Map([['a', 1]]),
};
state.self = state; // zirkuläre Referenz

const copy = structuredClone(state);

copy.cache.set('b', 2);
console.log(state.cache.size);           // Original bleibt unverändert
console.log(copy.created instanceof Date);
console.log(copy.self === copy);         // Zirkularität bleibt erhalten
console.log(copy === state);
1 true true false

Empfangene Nachricht unabhängig verarbeiten und Snapshot sichern

// worker.js
const history = [];

self.addEventListener('message', (event) => {
  const job = event.data;
  // Snapshot des Eingangszustands sichern, bevor er verändert wird
  history.push(structuredClone(job));

  job.items = job.items.map((n) => n * 2);
  job.done = true;

  self.postMessage({ result: job, original: history.at(-1) });
});

// main.js
// const worker = new Worker('worker.js');
// worker.onmessage = (e) => console.log(e.data);
// worker.postMessage({ items: [1, 2, 3], done: false });
{ result: { items: [2, 4, 6], done: true }, original: { items: [1, 2, 3], done: false } }

ArrayBuffer per transfer verschieben statt kopieren

// worker.js
const buffer = new ArrayBuffer(16 * 1024 * 1024); // 16 MB

const moved = structuredClone(buffer, { transfer: [buffer] });

console.log(moved.byteLength);  // Speicher gehört jetzt dem Klon
console.log(buffer.byteLength); // Original ist detached
16777216 0

Nicht klonbare Werte abfangen

// worker.js
const config = {
  name: 'export',
  onDone: () => console.log('fertig'), // Funktionen sind nicht klonbar
};

try {
  structuredClone(config);
} catch (err) {
  console.log(err.name);
}

// Abhilfe: nur die Daten klonen
const { onDone, ...data } = config;
console.log(structuredClone(data));
DataCloneError { name: 'export' }

// Wichtig · Fallstricke

  • Nicht klonbar: Funktionen, DOM-Knoten (in Workern ohnehin nicht vorhanden), Error-Objekte mit eigenen nicht klonbaren Eigenschaften, WeakMap/WeakSet, Symbol und Proxy-Objekte. Sie lösen einen DataCloneError aus.
  • Prototyp geht verloren: Instanzen eigener Klassen werden zu einfachen Objekten. Getter, Setter und Methoden fallen weg, und instanceof MeineKlasse ergibt anschließend false.
  • Property-Deskriptoren (z. B. writable: false) und Eigenschaften mit Symbol als Schlüssel werden nicht übernommen. Bei RegExp wird lastIndex nicht mitkopiert.
  • Nach einem transfer ist das Original unbrauchbar: Ein ArrayBuffer hat dann byteLength === 0, und wer weiter darauf zugreift, bekommt oft einen TypeError.
  • Performance: Tiefe Kopien großer Strukturen kosten Zeit und Speicher. Große Binärdaten besser per transfer verschieben oder SharedArrayBuffer nutzen. Letzteres setzt Cross-Origin-Isolation voraus.
  • Kompatibilität: Unterstützt seit Chrome/Edge 98, Firefox 94, Safari 15.4 und Node.js 17. Für ältere Umgebungen gibt es Polyfills (z. B. über core-js), die aber nicht alle Typen abdecken.