SharedArrayBuffer
SharedArrayBuffer
对象用于表示通用原始二进制数据缓冲区,类似于 ArrayBuffer
对象,但它可以用来在共享内存上创建视图。SharedArrayBuffer
不是 可传输对象,与可传输的 ArrayBuffer
不同。
描述
要使用来自集群中一个代理的 SharedArrayBuffer
对象与另一个代理共享内存(代理可以是网页的主程序或其某个 Web 工作线程),可以使用 postMessage
和 结构化克隆。
结构化克隆算法接受 SharedArrayBuffer
对象和映射到 SharedArrayBuffer
对象的类型化数组。在这两种情况下,SharedArrayBuffer
对象都会传输到接收方,从而在接收代理中生成一个新的私有 SharedArrayBuffer
对象(就像 ArrayBuffer
一样)。但是,这两个 SharedArrayBuffer
对象引用的共享数据块是同一个数据块,并且对一个代理中块的副作用最终会在另一个代理中可见。
const sab = new SharedArrayBuffer(1024);
worker.postMessage(sab);
可以在工作线程或主线程中同时创建和更新共享内存。根据系统(CPU、操作系统、浏览器)的不同,更改传播到所有上下文可能需要一段时间。要进行同步,需要使用 原子 操作。
某些 Web API 使用 SharedArrayBuffer
对象,例如
安全要求
鉴于 2018 年初 发生的 幽灵 漏洞,共享内存和高分辨率计时器实际上已被 禁用。2020 年,一种新的安全方法已标准化,以重新启用共享内存。
作为基本要求,您的文档需要处于 安全上下文 中。
对于顶级文档,需要设置两个标头以隔离站点的跨源访问
Cross-Origin-Opener-Policy
,其值为same-origin
(保护您的来源免受攻击者的侵害)Cross-Origin-Embedder-Policy
,其值为require-corp
或credentialless
(保护受害者免受您的来源侵害)
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
要检查跨源隔离是否成功,您可以针对 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
对象不再抛出异常,因此跨线程的共享内存可用。
嵌套文档和专用工作线程也需要设置 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
对象的基础 buffer
是 SharedArrayBuffer
。因此,上面列出的在工作线程之间共享 SharedArrayBuffer
的要求也适用于共享 WebAssembly.Memory
。
WebAssembly 线程提案还定义了一组新的 原子 指令。就像 SharedArrayBuffer
及其方法始终启用(并且只有线程之间的共享受限于新的标头)一样,WebAssembly 原子指令也始终允许。
扩展 SharedArrayBuffer
通过在调用 SharedArrayBuffer()
构造函数时包含 maxByteLength
选项,可以使 SharedArrayBuffer
对象可扩展。您可以通过访问其 growable
和 maxByteLength
属性分别查询 SharedArrayBuffer
是否可扩展及其最大大小。您可以使用 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 语言规范 # sec-sharedarraybuffer-objects |
浏览器兼容性
BCD 表格仅在启用 JavaScript 的浏览器中加载。
另请参阅
原子操作
ArrayBuffer
- JavaScript 类型化数组 指南
- Web Workers
- 共享内存 – 简短教程(TC39 ecmascript-sharedmem 建议)
- JavaScript 新并行原语初探(hacks.mozilla.org,2016)
- COOP 和 COEP 解释(Chrome 团队,2020)
跨源打开程序策略
跨源嵌入程序策略
跨源资源策略
Window.crossOriginIsolated
和WorkerGlobalScope.crossOriginIsolated
- Android Chrome 88 和桌面版 Chrome 92 中的 SharedArrayBuffer 更新(developer.chrome.com,2021)