Start · Sprachen · JavaScript · Referenz · ArrayBuffer.prototype.transfer()

ArrayBuffer.prototype.transfer()

Methode

Erstellt einen neuen <code>ArrayBuffer</code> mit demselben Byte-Inhalt (optional mit neuer Länge) und trennt den ursprünglichen Puffer ab (detach).

seit JavaScript ES2024 (Baseline 2024: Chrome 114, Firefox 122, Sa Kategorie: method-property

Signatur

ArrayBuffer.prototype.transfer(newLength)

Beschreibung

transfer() überträgt den Inhalt eines ArrayBuffer in einen neuen Puffer und macht den alten Puffer danach unbrauchbar („detached“). Seine byteLength ist dann 0, und jeder Zugriff über daran gebundene TypedArrays oder DataViews schlägt fehl oder liefert nichts mehr. Das entspricht einer Übergabe des Besitzes: Nach dem Aufruf verweist nur noch der neue Puffer auf die Daten.

Da die Engine den zugrunde liegenden Speicher oft einfach umhängt, statt ihn zu kopieren, ist transfer() meist deutlich günstiger als eine manuelle Kopie mit slice(). Mit dem optionalen Parameter newLength lässt sich der Puffer dabei gleich vergrößern (neue Bytes werden mit 0 gefüllt) oder verkleinern (überschüssige Bytes werden verworfen).

Typische Einsatzfälle:

  • Eine API bekommt einen Puffer, und der Aufrufer soll ihn danach nicht mehr verändern können (Schutz vor nachträglicher Manipulation).
  • Einen Puffer effizient vergrößern oder verkleinern, ohne Daten doppelt im Speicher zu halten.
  • Den Zustand „detached“ bewusst herbeiführen, analog zu structuredClone(buf, { transfer: [buf] }) oder postMessage mit Transfer-Liste.

Der neue Puffer behält die Größenänderbarkeit des Originals: Ist der alte Puffer resizable (mit maxByteLength erzeugt), ist es auch der neue, mit derselben maxByteLength. Soll das Ergebnis fest sein, nimmt man transferToFixedLength().

Parameter

Name Typ Default Beschreibung
$newLength number this.byteLength Die byteLength des neuen Puffers. Ist sie größer als die bisherige, werden die zusätzlichen Bytes mit 0 gefüllt, ist sie kleiner, wird abgeschnitten. Bei einem größenänderbaren Puffer darf sie maxByteLength nicht überschreiten.

Rückgabewert

Typ
ArrayBuffer
Beschreibung
Ein neuer ArrayBuffer mit dem Inhalt des Originals (ggf. gekürzt oder mit Nullen aufgefüllt). Die Größenänderbarkeit und maxByteLength werden vom Original übernommen. Der ursprüngliche Puffer ist danach abgetrennt (detached === true).

Beispiele

Grundlagen: Inhalt übertragen, Original wird abgetrennt

const buf = new ArrayBuffer(8);
const view = new Uint8Array(buf);
view[0] = 42;

const moved = buf.transfer();

console.log(buf.detached, buf.byteLength);   // Original ist leer
console.log(moved.detached, moved.byteLength);
console.log(new Uint8Array(moved)[0]);
console.log(view.length);                    // alte Sicht ist unbrauchbar
true 0 false 8 42 0

Puffer vergrößern und verkleinern

const buf = new ArrayBuffer(4);
new Uint8Array(buf).set([1, 2, 3, 4]);

// Vergrößern: neue Bytes sind 0
const bigger = buf.transfer(6);
console.log([...new Uint8Array(bigger)]);

// Verkleinern: überschüssige Bytes fallen weg
const smaller = bigger.transfer(2);
console.log([...new Uint8Array(smaller)]);
console.log(bigger.detached);
[1, 2, 3, 4, 0, 0] [1, 2] true

Praxis: Puffer an eine Funktion übergeben und vor Manipulation schützen

const processAsync = async (input) => {
  // Besitz übernehmen – der Aufrufer kann die Daten nicht mehr ändern
  const owned = input.transfer();
  await new Promise((resolve) => setTimeout(resolve, 10));
  const bytes = new Uint8Array(owned);
  return bytes.reduce((sum, b) => sum + b, 0);
};

const data = new Uint8Array([10, 20, 30]).buffer;
const resultPromise = processAsync(data);

// Nachträglicher Schreibversuch läuft ins Leere
new Uint8Array(data)[0] = 255;  // Sicht hat Länge 0, Zuweisung wird ignoriert

console.log(await resultPromise);
60

Resizable-Eigenschaft bleibt erhalten

const rbuf = new ArrayBuffer(4, { maxByteLength: 16 });
const t1 = rbuf.transfer();
console.log(t1.resizable, t1.maxByteLength);

t1.resize(12);
console.log(t1.byteLength);

try {
  t1.transfer(32); // größer als maxByteLength
} catch (e) {
  console.log(e.constructor.name);
}
true 16 12 RangeError

// Wichtig · Fallstricke

  • Abgetrennte Puffer: Ruft man transfer() auf einem bereits abgetrennten Puffer auf, wird ein TypeError ausgelöst. Mit buf.detached lässt sich das vorher prüfen.
  • Alte Sichten: TypedArrays und DataViews auf dem Original werden nicht automatisch umgehängt. TypedArrays haben danach die Länge 0, Zugriffe über eine DataView lösen einen TypeError aus. Neue Sichten müssen auf dem zurückgegebenen Puffer erzeugt werden.
  • RangeError: Wird ausgelöst, wenn newLength bei einem größenänderbaren Puffer maxByteLength überschreitet oder negativ bzw. zu groß ist.
  • SharedArrayBuffer: Hat keine transfer()-Methode, geteilter Speicher lässt sich nicht abtrennen. Auch nicht abtrennbare Puffer, z. B. WebAssembly.Memory.buffer, lösen einen TypeError aus.
  • Performance: Ohne Längenänderung (oder bei nicht größenänderbaren Puffern) kann die Engine meist ganz ohne Kopie auskommen. Bei geänderter Länge kann trotzdem kopiert werden, das hängt von der Implementierung ab.
  • Kompatibilität: Neu in ES2024. Verfügbar ab Chrome/Edge 114, Firefox 122, Safari 17.4 und Node.js 21. Für ältere Umgebungen gibt es als Ausweichlösung structuredClone(buf, { transfer: [buf] }), allerdings ohne Längenänderung.