SharedArrayBuffer

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

¥The SharedArrayBuffer object is used to represent a generic raw binary data buffer, similar to the ArrayBuffer object, but in a way that they can be used to create views on shared memory. A SharedArrayBuffer is not a Transferable Object, unlike an ArrayBuffer which is transferable.

描述

¥Description

要使用 SharedArrayBuffer 对象从集群中的一个代理程序共享内存到另一个代理程序(代理程序是网页的主程序或其 Web Worker 之一),需要使用 postMessage结构化克隆

¥To share memory using SharedArrayBuffer objects from one agent in the cluster to another (an agent is either the web page's main program or one of its web workers), postMessage and structured cloning is used.

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

¥The structured clone algorithm accepts SharedArrayBuffer objects and typed arrays mapped onto SharedArrayBuffer objects. In both cases, the SharedArrayBuffer object is transmitted to the receiver resulting in a new, private SharedArrayBuffer object in the receiving agent (just as for ArrayBuffer). However, the shared data block referenced by the two SharedArrayBuffer objects is the same data block, and a side effect to the block in one agent will eventually become visible in the other agent.

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

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

¥Shared memory can be created and updated simultaneously in workers or the main thread. Depending on the system (the CPU, the OS, the Browser) it can take a while until the change is propagated to all contexts. To synchronize, atomic operations are needed.

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

¥SharedArrayBuffer objects are used by some web APIs, such as:

安全要求

¥Security requirements

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

¥Shared memory and high-resolution timers were effectively disabled at the start of 2018 in light of Spectre. In 2020, a new, secure approach has been standardized to re-enable shared memory.

作为基准要求,你的文档需要采用 安全上下文

¥As a baseline requirement, your document needs to be in a secure context.

对于顶层文档,需要设置两个标头来跨源隔离你的站点:

¥For top-level documents, two headers need to be set to cross-origin isolate your site:

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

要检查跨源隔离是否成功,你可以针对窗口和工作线程上下文可用的 crossOriginIsolated 属性进行测试:

¥To check if cross origin isolation has been successful, you can test against the crossOriginIsolated property available to window and worker contexts:

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 对象,因此跨线程的共享内存可用。

¥With these two headers set, postMessage() no longer throws for SharedArrayBuffer objects and shared memory across threads is therefore available.

嵌套文档和专用工作人员也需要设置 Cross-Origin-Embedder-Policy 标头,并具有相同的值。同源嵌套文档和子资源不需要进一步更改。同站点(但跨域)嵌套文档和子资源需要设置 Cross-Origin-Resource-Policy 标头并使用 same-site 作为值。而他们的跨域(和跨站点)对应者需要设置相同的标头,并将 cross-origin 作为值。请注意,将 Cross-Origin-Resource-Policy 标头设置为 same-origin 之外的任何其他值都会使资源遭受潜在攻击,例如 幽灵

¥Nested documents and dedicated workers need to set the Cross-Origin-Embedder-Policy header as well, with the same value. No further changes are needed for same-origin nested documents and subresources. Same-site (but cross-origin) nested documents and subresources need to set the Cross-Origin-Resource-Policy header with same-site as value. And their cross-origin (and cross-site) counterparts need to set the same header with cross-origin as value. Note that setting the Cross-Origin-Resource-Policy header to any other value than same-origin opens up the resource to potential attacks, such as Spectre.

请注意,Cross-Origin-Opener-Policy 标头限制了你保留对弹出窗口的引用的能力。两个顶层窗口上下文之间的直接访问本质上只有在它们具有相同来源并且携带具有相同两个值的相同两个标头时才有效。

¥Note that the Cross-Origin-Opener-Policy header limits your ability to retain a reference to popups. Direct access between two top-level window contexts essentially only work if they are same-origin and carry the same two headers with the same two values.

API 可用性

¥API availability

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

¥Depending on whether the above security measures are taken, the various memory-sharing APIs have different availabilities:

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

WebAssembly 共享内存

¥WebAssembly shared memory

可以使用 shared 构造函数标志创建 WebAssembly.Memory 对象。当此标志设置为 true 时,构造的 Memory 对象可以通过 postMessage() 在工作人员之间共享,就像 SharedArrayBuffer 一样,而 Memory 对象的支持 bufferSharedArrayBuffer。因此,上面列出的在工人之间共享 SharedArrayBuffer 的要求也适用于共享 WebAssembly.Memory

¥WebAssembly.Memory objects can be created with the shared constructor flag. When this flag is set to true, the constructed Memory object can be shared between workers via postMessage(), just like SharedArrayBuffer, and the backing buffer of the Memory object is a SharedArrayBuffer. Therefore, the requirements listed above for sharing a SharedArrayBuffer between workers also apply to sharing a WebAssembly.Memory.

WebAssembly Threads 提案还定义了一组新的 atomic 指令。正如 SharedArrayBuffer 及其方法被无条件启用(并且只有线程之间的共享在新标头上被门控)一样,WebAssembly 原子指令也被无条件允许。

¥The WebAssembly Threads proposal also defines a new set of atomic instructions. Just as SharedArrayBuffer and its methods are unconditionally enabled (and only sharing between threads is gated on the new headers), the WebAssembly atomic instructions are also unconditionally allowed.

增加 SharedArrayBuffer

¥Growing SharedArrayBuffers

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

¥SharedArrayBuffer objects can be made growable by including the maxByteLength option when calling the SharedArrayBuffer() constructor. You can query whether a SharedArrayBuffer is growable and what its maximum size is by accessing its growable and maxByteLength properties, respectively. You can assign a new size to a growable SharedArrayBuffer with a grow() call. New bytes are initialized to 0.

这些功能使 SharedArrayBuffer 的增长更加高效 - 否则,你必须使用新大小制作缓冲区的副本。在这方面,它还使 JavaScript 与 WebAssembly 同等(Wasm 线性内存可以使用 WebAssembly.Memory.prototype.grow() 调整大小)。

¥These features make growing SharedArrayBuffers more efficient — otherwise, you have to make a copy of the buffer with a new size. It also gives JavaScript parity with WebAssembly in this regard (Wasm linear memory can be resized with WebAssembly.Memory.prototype.grow()).

出于安全原因,SharedArrayBuffer 无法缩小尺寸,只能增大。

¥For security reasons, SharedArrayBuffers cannot be reduced in size, only grown.

构造函数

¥Constructor

SharedArrayBuffer()

创建一个新的 SharedArrayBuffer 对象。

静态属性

¥Static properties

SharedArrayBuffer[@@species]

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

实例属性

¥Instance properties

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

¥These properties are defined on SharedArrayBuffer.prototype and shared by all SharedArrayBuffer instances.

SharedArrayBuffer.prototype.byteLength

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

SharedArrayBuffer.prototype.constructor

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

SharedArrayBuffer.prototype.growable

只读。如果 SharedArrayBuffer 可以生长,则返回 true;如果不能,则返回 false

SharedArrayBuffer.prototype.maxByteLength

SharedArrayBuffer 可以增长到的只读最大长度(以字节为单位)。这是在构造数组时确定的并且无法更改。

SharedArrayBuffer.prototype[@@toStringTag]

@@toStringTag 属性的初始值为字符串 "SharedArrayBuffer"。该属性在 Object.prototype.toString() 中使用。

实例方法

¥Instance methods

SharedArrayBuffer.prototype.grow()

SharedArrayBuffer 增长到指定大小(以字节为单位)。

SharedArrayBuffer.prototype.slice()

返回一个新的 SharedArrayBuffer,其内容是从 begin(含)到 end(不包括)的 SharedArrayBuffer 字节的副本。如果 beginend 为负数,则它指的是从数组末尾开始的索引,而不是从开头开始的索引。

示例

¥Examples

创建一个新的 SharedArrayBuffer

¥Creating a new SharedArrayBuffer

js
const sab = new SharedArrayBuffer(1024);

对 SharedArrayBuffer 进行切片

¥Slicing the 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 缓冲区中使用它

¥Using it in a WebGL buffer

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

规范

Specification
ECMAScript Language Specification
# sec-sharedarraybuffer-objects

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看