SharedArrayBuffer

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since December 2021.

Das SharedArrayBuffer-Objekt wird verwendet, um einen generischen, rohen binären Datenpuffer darzustellen, ähnlich dem ArrayBuffer-Objekt, jedoch so, dass sie zur Erstellung von Ansichten auf den geteilten Speicher genutzt werden können. Ein SharedArrayBuffer ist kein transferierbares Objekt, im Gegensatz zu einem ArrayBuffer, der transferierbar ist.

Beschreibung

Um Speicher mithilfe von SharedArrayBuffer-Objekten von einem Agenten im Cluster zu einem anderen zu teilen (ein Agent ist entweder das Hauptprogramm der Webseite oder einer ihrer Web-Worker), wird postMessage und das strukturierte Klonen verwendet.

Der Strukturierte Klon-Algorithmus akzeptiert SharedArrayBuffer-Objekte und mit SharedArrayBuffer-Objekten abgebildete typisierte Arrays. In beiden Fällen wird das SharedArrayBuffer-Objekt zum Empfänger übertragen, was zu einem neuen, privaten SharedArrayBuffer-Objekt im empfangenden Agenten führt (wie bei ArrayBuffer). Jedoch ist der mit den beiden SharedArrayBuffer-Objekten referenzierte gemeinsame Datenblock derselbe Datenblock, und eine Nebenwirkung auf den Block in einem Agenten wird schließlich im anderen Agenten sichtbar.

js
const sab = new SharedArrayBuffer(1024);
worker.postMessage(sab);

Geteilter Speicher kann gleichzeitig in Workern oder dem Haupt-Thread erstellt und aktualisiert werden. Je nach System (CPU, Betriebssystem, Browser) kann es eine Weile dauern, bis die Änderung in allen Kontexten propagiert wird. Zur Synchronisation sind atomare Operationen nötig.

SharedArrayBuffer-Objekte werden von einigen Web-APIs verwendet, wie zum Beispiel:

Sicherheitsanforderungen

Geteilter Speicher und Hochauflösungs-Timer wurden Anfang 2018 effektiv deaktiviert im Hinblick auf Spectre. 2020 wurde ein neuer, sicherer Ansatz standardisiert, um geteilten Speicher wieder zu aktivieren.

Als grundlegende Anforderung muss Ihr Dokument in einem sicheren Kontext sein.

Für Top-Level-Dokumente müssen zwei Header gesetzt werden, um Ihre Website zu Cross-Origin-Isolieren:

http
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Um zu überprüfen, ob die Cross-Origin-Isolierung erfolgreich war, können Sie die Window.crossOriginIsolated-Eigenschaft oder die WorkerGlobalScope.crossOriginIsolated-Eigenschaft testen, die in Fenster- und Worker-Kontexten verfügbar ist:

js
const myWorker = new Worker("worker.js");

if (crossOriginIsolated) {
  const buffer = new SharedArrayBuffer(16);
  myWorker.postMessage(buffer);
} else {
  const buffer = new ArrayBuffer(16);
  myWorker.postMessage(buffer);
}

Mit diesen beiden gesetzten Headern wirft postMessage() nicht länger für SharedArrayBuffer-Objekte und damit ist geteilter Speicher über Threads hinweg verfügbar.

Eingebettete Dokumente und dedizierte Worker müssen ebenfalls den Cross-Origin-Embedder-Policy-Header mit demselben Wert setzen. Keine weiteren Änderungen sind für gleichherkömmliche eingebettete Dokumente und Subressourcen nötig. Gleichseitige (aber Cross-Origin) eingebettete Dokumente und Subressourcen müssen den Cross-Origin-Resource-Policy-Header mit dem Wert same-site setzen. Und ihre Cross-Origin (und Cross-Site) Gegenstücke müssen denselben Header mit dem Wert cross-origin setzen. Beachten Sie, dass das Setzen des Cross-Origin-Resource-Policy-Headers auf einen anderen Wert als same-origin die Ressource für potenzielle Angriffe wie Spectre öffnet.

Beachten Sie, dass der Cross-Origin-Opener-Policy-Header Ihre Fähigkeit einschränkt, eine Referenz zu Popups zu behalten. Direkter Zugriff zwischen zwei Top-Level-Fenster-Kontexten funktioniert im Wesentlichen nur, wenn sie gleichherkömmlich sind und dieselben zwei Header mit denselben zwei Werten tragen.

API-Verfügbarkeit

Abhängig von den oben genannten Sicherheitsmaßnahmen haben die verschiedenen Speicherfreigabe-APIs unterschiedliche Verfügbarkeiten:

  • Das Atomics-Objekt ist immer verfügbar.
  • SharedArrayBuffer-Objekte sind grundsätzlich immer verfügbar, aber leider ist der Konstruktor am globalen Objekt versteckt, es sei denn, die oben genannten zwei Header sind gesetzt, um die Kompatibilität mit Webinhalten zu gewährleisten. Es besteht Hoffnung, dass diese Einschränkung in der Zukunft entfernt werden kann. WebAssembly.Memory kann immer noch verwendet werden, um eine Instanz zu erhalten.
  • Sofern die oben genannten zwei Header nicht gesetzt sind, werfen die verschiedenen postMessage()-APIs für SharedArrayBuffer-Objekte. Sind sie gesetzt, funktionieren postMessage() auf Window-Objekten und dedizierten Workern und erlauben das Teilen von Speicher.

WebAssembly-geteilter Speicher

WebAssembly.Memory-Objekte können mit dem shared-Konstruktor-Flag erstellt werden. Wenn dieses Flag auf true gesetzt ist, kann das erstellte Memory-Objekt zwischen Workern über postMessage() geteilt werden, genau wie SharedArrayBuffer, und der zugrunde liegende buffer des Memory-Objekts ist ein SharedArrayBuffer. Daher gelten die oben aufgelisteten Anforderungen für das Teilen eines SharedArrayBuffer zwischen Workern auch für das Teilen eines WebAssembly.Memory.

Der WebAssembly Threads-Vorschlag definiert auch eine neue Reihe von atomaren Anweisungen. Genau wie SharedArrayBuffer und seine Methoden unconditionally enabled sind (und nur das Teilen zwischen Threads auf die neuen Header beschränkt ist), sind die WebAssembly atomaren Anweisungen auch bedingungslos erlaubt.

Wachsende SharedArrayBuffers

SharedArrayBuffer-Objekte können wachstumsfähig gemacht werden, indem die Option maxByteLength beim Aufruf des SharedArrayBuffer()-Konstruktors einbezogen wird. Sie können ermitteln, ob ein SharedArrayBuffer wachstumsfähig ist und welches seine maximale Größe ist, indem Sie jeweils auf seine growable- und maxByteLength-Eigenschaften zugreifen. Sie können einem wachstumsfähigen SharedArrayBuffer eine neue Größe zuweisen, indem Sie einen grow()-Aufruf durchführen. Neue Bytes werden mit 0 initialisiert.

Diese Features machen das Wachsen von SharedArrayBuffers effizienter – ansonsten müssten Sie eine Kopie des Puffers mit einer neuen Größe anfertigen. Es gibt auch eine Parität mit WebAssembly in dieser Hinsicht (Wasm lineare Speicher kann mit WebAssembly.Memory.prototype.grow()) verändert werden.

Aus Sicherheitsgründen können SharedArrayBuffers nicht verkleinert, sondern nur vergrößert werden.

Konstruktor

SharedArrayBuffer()

Erstellt ein neues SharedArrayBuffer-Objekt.

Statische Eigenschaften

SharedArrayBuffer[Symbol.species]

Gibt den Konstruktor zurück, der verwendet wird, um Rückgabewerte von SharedArrayBuffer-Methoden zu konstruieren.

Instanzeigenschaften

Diese Eigenschaften sind auf SharedArrayBuffer.prototype definiert und werden von allen SharedArrayBuffer-Instanzen geteilt.

SharedArrayBuffer.prototype.byteLength

Die Größe in Bytes des Arrays. Diese wird bei der Konstruktion des Arrays festgelegt und kann nur mit der SharedArrayBuffer.prototype.grow()-Methode geändert werden, wenn der SharedArrayBuffer wachstumsfähig ist.

SharedArrayBuffer.prototype.constructor

Die Konstruktionsfunktion, die das Instanz-Objekt erstellt hat. Für SharedArrayBuffer-Instanzen ist der Anfangswert der SharedArrayBuffer-Konstruktor.

SharedArrayBuffer.prototype.growable

Nur-Lese-Attribut. Gibt true zurück, wenn der SharedArrayBuffer wachsen kann, oder false, wenn nicht.

SharedArrayBuffer.prototype.maxByteLength

Die maximal mögliche Länge in Bytes, auf die der SharedArrayBuffer wachsen kann. Diese wird bei der Konstruktion des Arrays festgelegt und kann nicht geändert werden.

SharedArrayBuffer.prototype[Symbol.toStringTag]

Der Anfangswert der [Symbol.toStringTag]-Eigenschaft ist der String "SharedArrayBuffer". Diese Eigenschaft wird in Object.prototype.toString() verwendet.

Instanzmethoden

SharedArrayBuffer.prototype.grow()

Vergrößert den SharedArrayBuffer auf die angegebene Größe in Bytes.

SharedArrayBuffer.prototype.slice()

Gibt einen neuen SharedArrayBuffer zurück, dessen Inhalt eine Kopie der Bytes dieses SharedArrayBuffer von begin, einschließlich bis end, ausschließlich ist. Wenn begin oder end negativ ist, bezieht es sich auf einen Index vom Ende des Arrays, im Gegensatz zum Anfang.

Beispiele

Erstellen eines neuen SharedArrayBuffer

js
const sab = new SharedArrayBuffer(1024);

Slicing des SharedArrayBuffer

js
sab.slice(); // SharedArrayBuffer { byteLength: 1024 }
sab.slice(2); // SharedArrayBuffer { byteLength: 1022 }
sab.slice(-2); // SharedArrayBuffer { byteLength: 2 }
sab.slice(0, 1); // SharedArrayBuffer { byteLength: 1 }

Verwendung in einem WebGL-Puffer

js
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, sab, gl.STATIC_DRAW);

Spezifikationen

Specification
ECMAScript Language Specification
# sec-sharedarraybuffer-objects

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch