SharedArrayBuffer

基线 广泛可用

此功能已得到良好建立,并且可在许多设备和浏览器版本上运行。它自以下版本以来在浏览器中可用 2021 年 12 月.

SharedArrayBuffer 对象用于表示通用原始二进制数据缓冲区,类似于 ArrayBuffer 对象,但它可以用来在共享内存上创建视图。SharedArrayBuffer 不是 可传输对象,与可传输的 ArrayBuffer 不同。

描述

要使用来自集群中一个代理的 SharedArrayBuffer 对象与另一个代理共享内存(代理可以是网页的主程序或其某个 Web 工作线程),可以使用 postMessage结构化克隆

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

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

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

某些 Web API 使用 SharedArrayBuffer 对象,例如

安全要求

鉴于 2018 年初 发生的 幽灵 漏洞,共享内存和高分辨率计时器实际上已被 禁用。2020 年,一种新的安全方法已标准化,以重新启用共享内存。

作为基本要求,您的文档需要处于 安全上下文 中。

对于顶级文档,需要设置两个标头以隔离站点的跨源访问

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

要检查跨源隔离是否成功,您可以针对 Window.crossOriginIsolated 属性或 WorkerGlobalScope.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 对象不再抛出异常,因此跨线程的共享内存可用。

嵌套文档和专用工作线程也需要设置 Cross-Origin-Embedder-Policy 标头,并使用相同的值。对于同源嵌套文档和子资源,无需进行其他更改。同站点(但跨源)嵌套文档和子资源需要设置 Cross-Origin-Resource-Policy 标头,其值为 same-site。它们的跨源(和跨站点)对应项需要设置相同的标头,其值为 cross-origin。请注意,将 Cross-Origin-Resource-Policy 标头设置为 same-origin 以外的任何其他值都会使资源容易受到潜在攻击,例如 幽灵

请注意,Cross-Origin-Opener-Policy 标头会限制您保留对弹出窗口的引用的能力。两个顶级窗口上下文之间的直接访问基本上仅在它们是同源且带有相同两个标头和相同两个值时才有效。

API 可用性

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

  • Atomics 对象始终可用。
  • SharedArrayBuffer 对象原则上始终可用,但不幸的是,除非设置了上面提到的两个标头,否则全局对象上的构造函数会被隐藏,以确保与 Web 内容兼容。希望将来可以取消此限制。WebAssembly.Memory 仍可用于获取实例。
  • 除非设置了上面提到的两个标头,否则各种 postMessage() API 对于 SharedArrayBuffer 对象将抛出异常。如果设置了这些标头,则 Window 对象和专用工作线程上的 postMessage() 将起作用并允许内存共享。

WebAssembly 共享内存

WebAssembly.Memory 对象可以使用 shared 构造函数标志创建。当此标志设置为 true 时,构造的 Memory 对象可以通过 postMessage() 在工作线程之间共享,就像 SharedArrayBuffer 一样,并且 Memory 对象的基础 bufferSharedArrayBuffer。因此,上面列出的在工作线程之间共享 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,其内容是此 SharedArrayBufferbegin(包括)到 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 语言规范
# sec-sharedarraybuffer-objects

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅