SharedArrayBuffer
Baseline 广泛可用 *
SharedArrayBuffer 对象用于表示通用的原始二进制数据缓冲区,类似于 对象,但它们可用于创建对共享内存的视图。ArrayBufferSharedArrayBuffer 不是 ,而 Transferable ObjectArrayBuffer 是可传输的。
描述
要使用 SharedArrayBuffer 对象在集群中的一个代理(代理可以是网页的主程序或其 Web Worker 之一)与其他代理共享内存,需要使用 和 postMessagestructured cloning。
结构化克隆算法接受 SharedArrayBuffer 对象和映射到 SharedArrayBuffer 对象的类型化数组。在这两种情况下,SharedArrayBuffer 对象都会被传输给接收者,从而在接收代理中产生一个新的、私有的 SharedArrayBuffer 对象(就像 一样)。但是,两个 ArrayBufferSharedArrayBuffer 对象引用的共享数据块是同一个数据块,在一个代理中对该数据块的更改最终会在另一个代理中可见。
const sab = new SharedArrayBuffer(1024);
worker.postMessage(sab);
共享内存可以在 Worker 或主线程中同时创建和更新。根据系统(CPU、操作系统、浏览器)的不同,更改可能需要一段时间才能传播到所有上下文。为了同步,需要使用 操作。Atomics
SharedArrayBuffer 对象被一些 Web API 使用,例如
安全要求
鉴于 Spectre 的出现,共享内存和高分辨率计时器在 2018 年初被有效地 禁用。在 2020 年,一种新的、安全的方法被标准化,以重新启用共享内存。
要使用共享内存,您的文档必须处于 安全上下文 并且 跨源隔离。您可以使用 和 Window.crossOriginIsolated 属性来检查文档是否跨源隔离。WorkerGlobalScope.crossOriginIsolated
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.Memoryshared 构造函数标志创建。当此标志设置为 true 时,构造的 Memory 对象可以通过 postMessage() 在 Worker 之间共享,就像 SharedArrayBuffer 一样,并且 Memory 对象支持的 buffer 是一个 SharedArrayBuffer。因此,上述在 Worker 之间共享 SharedArrayBuffer 的要求同样适用于共享 WebAssembly.Memory。
WebAssembly 线程提案还定义了一组新的 原子 指令。就像 SharedArrayBuffer 及其方法被无条件启用一样(只有线程之间的共享受到新头信息的限制),WebAssembly 原子指令也被无条件允许。
扩展 SharedArrayBuffer
可以通过在调用 构造函数时包含 SharedArrayBuffer()maxByteLength 选项来使 SharedArrayBuffer 对象可扩展。您可以访问其 和 growable 属性来查询 maxByteLengthSharedArrayBuffer 是否可扩展以及其最大大小。您可以通过调用 方法来为可扩展的 grow()SharedArrayBuffer 分配新大小。新字节将被初始化为 0。
这些功能使得扩展 SharedArrayBuffer 更高效 — 否则,您必须创建一个具有新大小的缓冲区副本。它还使 JavaScript 在这方面与 WebAssembly 保持一致(Wasm 线性内存可以使用 进行大小调整)。WebAssembly.Memory.prototype.grow()
出于安全原因,SharedArrayBuffer 不能缩小,只能增大。
构造函数
-
创建一个新的
SharedArrayBuffer对象。
静态属性
-
返回用于构造
SharedArrayBuffer方法的返回值的构造函数。
实例属性
这些属性定义在 SharedArrayBuffer.prototype 上,并由所有 SharedArrayBuffer 实例共享。
-
数组的大小(以字节为单位)。此大小在数组构造时确定,并且只能使用
方法进行更改(如果SharedArrayBuffer.prototype.grow()SharedArrayBuffer可扩展)。 -
创建实例对象的构造函数。对于
SharedArrayBuffer实例,初始值为构造函数。SharedArrayBuffer -
只读。如果
SharedArrayBuffer可扩展,则返回true,否则返回false。 -
可读写的最大长度(以字节为单位),
SharedArrayBuffer可扩展至此。此长度在数组构造时确定,并且无法更改。 -
[Symbol.toStringTag]属性的初始值为字符串"SharedArrayBuffer"。此属性用于。Object.prototype.toString()
实例方法
-
将
SharedArrayBuffer扩展到指定的大小(以字节为单位)。 -
返回一个新的
SharedArrayBuffer,其内容是此SharedArrayBuffer中从begin(含)到end(不含)的字节副本。如果begin或end为负数,则表示相对于数组末尾的索引,而不是相对于开头的索引。
示例
创建新的 SharedArrayBuffer
const sab = new SharedArrayBuffer(1024);
切片 SharedArrayBuffer
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 缓冲区中使用它
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 |
浏览器兼容性
加载中…
另见
AtomicsArrayBuffer- JavaScript 类型化数组指南
- Web Workers
- TC39 ecmascript-sharedmem 提案中的 Shared Memory – a brief tutorial
- hacks.mozilla.org 上的 A Taste of JavaScript's New Parallel Primitives(2016 年)
- Chrome 团队的 COOP and COEP explained(2020 年)
Cross-Origin-Opener-PolicyCross-Origin-Embedder-PolicyCross-Origin-Resource-PolicyWindow.crossOriginIsolated和WorkerGlobalScope.crossOriginIsolated- developer.chrome.com 上的 SharedArrayBuffer updates in Android Chrome 88 and Desktop Chrome 92(2021 年)