进入到Stage4阶段
2023年9月份,可调节大小的ArrayBuffer这一提议进入到了Stage4阶段。各大执行环境也已经实现了该特性。
具体的API
具体的API涉及到ArrayBuffer和SharedArrayBuffer两个类型,列出清单如下:
ArrayBuffer
| 变化 | 类型 | API | 描述 |
|---|---|---|---|
| 修改 | 构造函数 | constructor(byteLength [, {maxByteLength}]) | 新增了 maxByteLength可选项,代表该ArrayBuffer允许的最大字节数,该参数表示该ArrayBuffer可以调节大小 |
| 新增 | 方法 | ArrayBuffer .prototype.resize(newByteLength) | 调节 ArrayBuffer的大小,resize(0)也是可以的 |
| 修改 | 方法 | ArrayBuffer.prototype.slice(start, end) | 返回一个新的不可调节大小的 ArrayBuffer |
| 新增 | Getter | ArrayBuffer.prototype.resizable | 是否可以调节大小 |
| 新增 | Getter | ArrayBuffer.prototype.maxByteLength | 允许的最大字节数 |
SharedArrayBuffer
| 变化 | 类型 | API | 描述 |
|---|---|---|---|
| 修改 | 构造函数 | constructor(byteLength [, {maxByteLength}]) | 新增了 maxByteLength可选项,代表允许的最大字节数,传入该参数表示可调节大小 |
| 新增 | 方法 | SharedArrayBuffer .prototype.grow(newByteLength) | 调节 SharedArrayBuffer的字节大小。要注意的是,只能调大不能调小,如果比byteLength小,该方法将会抛异常 |
| 修改 | 方法 | SharedArrayBuffer .prototype.slice(start, end) | 返回一个新的不可调节大小的 SharedArrayBuffer |
| 新增 | Getter | SharedArrayBuffer .prototype.growable | 是否可以调节大小,新建实例时有 maxByteLength 则代表可调节大小 |
| 新增 | Getter | SharedArrayBuffer .prototype.maxByteLength | 允许的最大字节数 |
ArrayBuffer是什么
ArrayBuffer的实例对象代表着一段通用的二进制数据缓冲区。通过该对象,Javascript可以以字节为单位直接存储和操作二进制数据。可以用来处理如图像、音频等数据。
所解决的问题
以前,我们创建一个ArrayBuffer时,会指定大小,一旦创建之后是没有办法修改其大小的:
const buffer = new ArrayBuffer(8);
// 字节长度是8,无法修改
console.log(buffer.byteLength);
如果我们确实需要改变其大小,我们只能重新创建一个新的ArrayBuffer对象。这会带来不小的性能损耗,代码也会变得复杂。
提议者举了两个具体的例子:WebAssembly和WebGPU。
WebAssembly
该新特性的提议者在提案中用WebAssembly举了个例子:
当WebAssembly的内存增长时,由于ArrayBuffer的大小不可以改变,所以它只能提供一个新的ArrayBuffer的实例,原有实例会变得不可用。这时Javascript不得不通过回调函数等形式同步的去更新其TypedArray,提议者用代码举例如下:
// wasm的内存一旦增长,其原有的ArrayBuffer就变得不可用了
let U8 = new Uint8Array(WebAssembly.Memory.buffer);
function derefPointerIntoWasmMemory(idx) {
// Uint8Array的长度如果是0,则说明wasm的内存已经增长了,从而导致了Uint8Array所依赖的ArrayBuffer已经不可用了,从而导致Uint8Array不可用。
if (U8.length === 0) {
// 这时需要重建Uint8Array,WebAssembly.Memory.buffer原先指向的内容已经不可用
U8 = new Uint8Array(WebAssembly.Memory.buffer);
}
doSomethingWith(U8[idx]);
}
WebGPU
WebGPU社区也希望缓冲区内存变化时,ArrayBuffer能够重复使用,而不是每次都重新新建ArrayBuffer实例,在动画期间,每次重新新建ArrayBuffer实例会增加垃圾回收的压力,从而导致卡顿。
原始提议文档
提议者还阐述了下面几项内容:
- 可调节大小的功能对
TypedArray的影响。 - 具体的实现方法。
- 安全问题。
- 为什么不直接将
ArrayBuffer改成可调节的,而是要加个参数? - 为什么要限制最大字节数?
- 为什么
SharedArrayBuffer不可以调小? SharedArrayBuffer的调大字节长度功能是如何与内存模型配合工作的?
如果想了解更多,可参考原始提议文档
此篇结束。