SharedArrayBuffer

Baseline 广泛可用 *

此功能已成熟,可在多种设备和浏览器版本上使用。自 2021 年 12 月以来,它已在所有浏览器中可用。

* 此特性的某些部分可能存在不同级别的支持。

SharedArrayBuffer 对象用于表示通用的原始二进制数据缓冲区,类似于 ArrayBuffer 对象,但它们可用于创建对共享内存的视图。SharedArrayBuffer 不是 Transferable Object,而 ArrayBuffer 是可传输的。

描述

要使用 SharedArrayBuffer 对象在集群中的一个代理(代理可以是网页的主程序或其 Web Worker 之一)与其他代理共享内存,需要使用 postMessagestructured cloning

结构化克隆算法接受 SharedArrayBuffer 对象和映射到 SharedArrayBuffer 对象的类型化数组。在这两种情况下,SharedArrayBuffer 对象都会被传输给接收者,从而在接收代理中产生一个新的、私有的 SharedArrayBuffer 对象(就像 ArrayBuffer 一样)。但是,两个 SharedArrayBuffer 对象引用的共享数据块是同一个数据块,在一个代理中对该数据块的更改最终会在另一个代理中可见。

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

共享内存可以在 Worker 或主线程中同时创建和更新。根据系统(CPU、操作系统、浏览器)的不同,更改可能需要一段时间才能传播到所有上下文。为了同步,需要使用 Atomics 操作。

SharedArrayBuffer 对象被一些 Web API 使用,例如

安全要求

鉴于 Spectre 的出现,共享内存和高分辨率计时器在 2018 年初被有效地 禁用。在 2020 年,一种新的、安全的方法被标准化,以重新启用共享内存。

要使用共享内存,您的文档必须处于 安全上下文 并且 跨源隔离。您可以使用 Window.crossOriginIsolatedWorkerGlobalScope.crossOriginIsolated 属性来检查文档是否跨源隔离。

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);
}

当跨源隔离时,postMessage() 不再因 SharedArrayBuffer 对象而抛出异常,因此跨线程共享内存可用。

API 可用性

根据是否采取了上述安全措施,各种内存共享 API 的可用性有所不同。

  • Atomics 对象始终可用。
  • 原则上,SharedArrayBuffer 对象始终可用,但遗憾的是,全局对象上的构造函数是隐藏的,除非设置了上述两个头信息,这是为了与 Web 内容兼容。希望将来可以取消此限制。WebAssembly.Memory 仍可用于获取实例。
  • 除非设置了上述两个头信息,否则各种 postMessage() API 在遇到 SharedArrayBuffer 对象时会抛出异常。如果设置了这些头信息,Window 对象和专用 Worker 上的 postMessage() 将正常工作并允许内存共享。

WebAssembly 共享内存

WebAssembly.Memory 对象可以使用 shared 构造函数标志创建。当此标志设置为 true 时,构造的 Memory 对象可以通过 postMessage() 在 Worker 之间共享,就像 SharedArrayBuffer 一样,并且 Memory 对象支持的 buffer 是一个 SharedArrayBuffer。因此,上述在 Worker 之间共享 SharedArrayBuffer 的要求同样适用于共享 WebAssembly.Memory

WebAssembly 线程提案还定义了一组新的 原子 指令。就像 SharedArrayBuffer 及其方法被无条件启用一样(只有线程之间的共享受到新头信息的限制),WebAssembly 原子指令也被无条件允许。

扩展 SharedArrayBuffer

可以通过在调用 SharedArrayBuffer() 构造函数时包含 maxByteLength 选项来使 SharedArrayBuffer 对象可扩展。您可以访问其 growablemaxByteLength 属性来查询 SharedArrayBuffer 是否可扩展以及其最大大小。您可以通过调用 grow() 方法来为可扩展的 SharedArrayBuffer 分配新大小。新字节将被初始化为 0。

这些功能使得扩展 SharedArrayBuffer 更高效 — 否则,您必须创建一个具有新大小的缓冲区副本。它还使 JavaScript 在这方面与 WebAssembly 保持一致(Wasm 线性内存可以使用 WebAssembly.Memory.prototype.grow() 进行大小调整)。

出于安全原因,SharedArrayBuffer 不能缩小,只能增大。

构造函数

SharedArrayBuffer()

创建一个新的 SharedArrayBuffer 对象。

静态属性

SharedArrayBuffer[Symbol.species]

返回用于构造 SharedArrayBuffer 方法的返回值的构造函数。

实例属性

这些属性定义在 SharedArrayBuffer.prototype 上,并由所有 SharedArrayBuffer 实例共享。

SharedArrayBuffer.prototype.byteLength

数组的大小(以字节为单位)。此大小在数组构造时确定,并且只能使用 SharedArrayBuffer.prototype.grow() 方法进行更改(如果 SharedArrayBuffer 可扩展)。

SharedArrayBuffer.prototype.constructor

创建实例对象的构造函数。对于 SharedArrayBuffer 实例,初始值为 SharedArrayBuffer 构造函数。

SharedArrayBuffer.prototype.growable

只读。如果 SharedArrayBuffer 可扩展,则返回 true,否则返回 false

SharedArrayBuffer.prototype.maxByteLength

可读写的最大长度(以字节为单位),SharedArrayBuffer 可扩展至此。此长度在数组构造时确定,并且无法更改。

SharedArrayBuffer.prototype[Symbol.toStringTag]

[Symbol.toStringTag] 属性的初始值为字符串 "SharedArrayBuffer"。此属性用于 Object.prototype.toString()

实例方法

SharedArrayBuffer.prototype.grow()

SharedArrayBuffer 扩展到指定的大小(以字节为单位)。

SharedArrayBuffer.prototype.slice()

返回一个新的 SharedArrayBuffer,其内容是此 SharedArrayBuffer 中从 begin(含)到 end(不含)的字节副本。如果 beginend 为负数,则表示相对于数组末尾的索引,而不是相对于开头的索引。

示例

创建新的 SharedArrayBuffer

js
const sab = new SharedArrayBuffer(1024);

切片 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 }

在 WebGL 缓冲区中使用它

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);

规范

规范
ECMAScript® 2026 语言规范
# sec-sharedarraybuffer-objects

浏览器兼容性

另见