这是一个老问题,但TypedArray
如果您有特定需要优化一些性能不佳的代码,则有理由使用 s。了解 JavaScript 中对象的重要一点是,TypedArray
它们是表示. 底层实际上表示要操作的连续二进制数据块,但我们需要一个视图来访问和操作该二进制数据的窗口。ArrayBuffer
ArrayBuffer
多个不同的对象ArrayBuffer
可以查看相同的单独(甚至重叠)范围。TypedArray
当您有两个TypedArray
共享相同ArrayBuffer
的对象时,set
操作非常快。这是因为机器正在使用一个连续的内存块。
这是一个例子。我们将创建一个ArrayBuffer
32 字节的长度,一个长度为 16Uint8Array
表示缓冲区的前 16 个字节,另一个长度为 16Uint8Array
表示最后 16 个字节:
var buffer = new ArrayBuffer(32);
var array1 = new Uint8Array(buffer, 0, 16);
var array2 = new Uint8Array(buffer, 16, 16);
现在我们可以在缓冲区的前半部分初始化一些值:
for (var i = 0; i < 16; i++) array1[i] = i;
console.log(array1); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
console.log(array2); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
然后非常有效地将这 8 个字节复制到缓冲区的后半部分:
array2.set(array1);
console.log(array1); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
console.log(array2); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
我们可以通过用另一个视图查看缓冲区来确认两个数组实际上共享同一个缓冲区。例如,我们可以使用Uint32Array
跨越整个 32 字节缓冲区的长度为 8 的值:
var array3 = new Uint32Array(buffer)
console.log(array3); // [50462976, 117835012, 185207048, 252579084,
// 50462976, 117835012, 185207048, 252579084]
我修改了一个 JSPerf 测试,我发现它展示了在同一个缓冲区上复制的巨大性能提升:
http://jsperf.com/typedarray-set-vs-loop/3
我们在 Chrome 和 Firefox 上获得了一个数量级的性能提升,它甚至比采用双倍长度的普通数组并将前半部分复制到后半部分要快得多。但是我们必须在这里考虑周期/内存权衡。只要我们引用了 an 的任何单个视图,ArrayBuffer
缓冲区的其余数据就不能被垃圾收集。为 ES7 Harmony 提出了一个ArrayBuffer.transfer
函数,通过让我们能够显式释放内存而无需等待垃圾收集器,以及动态增长ArrayBuffer
s 而不必复制的能力来解决这个问题。