在JavaScript中使用ArrayBuffer和类型化数组的位置?

时间:2017-02-23 13:13:30

标签: javascript arraybuffer

我正在从Node.js迁移到浏览器环境,我仍然对ArrayBuffer和类型化数组(例如Uint8Array)感到困惑。

我对使用类型化数组的位置以及直接使用ArrayBuffer的位置感到困惑。将一个转换为另一个并不难,反之亦然,但在何时使用?

例如,当我创建一个代表我代码中的一大块数据的对象时,它应该是ArrayBuffer还是Uint8Array?它取决于什么?

或者:我应该从函数中返回ArrayBuffer(例如,对于外部API)还是类型化数组?

请注意,我可以谷歌如何向这些类型化数组添加元素等;我缺少的是一些简短的一般指南,在哪里使用。特别是从节点缓冲区移动时。

1 个答案:

答案 0 :(得分:56)

概念

ArrayBuffer表示物理内存中的字节数组。 ArrayBuffer是字节的实际存储空间,但很少直接使用 - 实际上,您无法直接读取ArrayBuffer的内容,只能为其传递引用。另一方面,它们用于服务器和客户端之间的二进制数据传输,或者用于通过Blob从用户的文件系统传输。

ArrayBuffer byte array in memory
内存中的ArrayBuffer字节数组 - 每个索引等于一个字节。 ArrayBuffer在内存中对齐。

要阅读ArrayBuffer的内容,您需要使用视图。它位于顶部并提供了一个" api"以不同的宽度类型或任意方式访问字节。

与宽度相关的视图

根据您的需要使用不同的视图。如果你只需要读取字节值,即。在-128和127之间的有符号值 - 或 - 0-255之间的无符号值,您将使用Int8Array或Uint8Array。请注意,他们的名字有点误导"因为它们是视图而不是数组,并且只引用底层的ArrayBuffer。

同样,您有Int8ArrayUint8ArrayUint8ClampedArrayInt16ArrayUint16ArrayInt32ArrayUint3Array的观看次数,Float32ArrayFloat64Array

除了* int8Arrays之外,其他人对ArrayBuffer的大小有一些要求。例如,Uint32Array视图必须位于可被4整除的ArrayBuffer之上,否则会引发错误。 * int 16个视图需要一个双字节边界。

这通常不是问题,因为您可以直接使用视图的构造函数指定索引数,并且会自动创建匹配的ArrayBuffer以满足这些要求。

由于ArrayBuffer是一个字节数组,因此* int16视图从中读取两个字节 - 或者,一个索引=两个字节,* int32四个,或一个索引=四个字节,依此类推。

Uint8Array和Uint8ClampedArray之间的主要区别在于,范围之外的值受普通数组的模数(例如256变为0)。在钳位阵列中,值被建议钳位(256变为255)。

*int16 view
Int16 / Uint16视图 - 每个索引代表两个字节并且是内存对齐的。

*int32 view
Int32 / Uint32和Float32视图 - 每个索引代表四个字节并且是内存对齐的。

Float64 view
Float64视图 - 每个索引代表八个字节并且是内存对齐的。

DataView的灵活性

然后是DataView。这适用于需要灵活的ArrayBuffer并且需要读取可变宽度和缓冲区中不一定是宽度或内存对齐的位置的情况。

例如,* int32索引将始终指向可分为四的内存位置。另一方面,DataView可以从位置5读取Uint32,并在内部处理所有需要的步骤(位移,屏蔽等),但代价是开销很小。

另一个不同之处在于,DataView不使用索引,而是使用它所代表的数据的绝对字节位置,并且它带有自己的方法来从/向任何位置读取或写入各种宽度。

DataView
DataView - 可以从任何位置和任何宽度读取。

在其他情况下,您可以使用几个引用相同底层ArrayBuffer的不同视图。

当前整数不存在64位视图,但似乎是proposed for ES8

SharedArrayBuffers

提及可在网络工作人员中使用的新SharedArrayBuffers也很有用。

您可以(并且仍然可以)在某些浏览器中使用transferable objects,但SharedArrayBuffers在内存保持不变的意义上更有效,只传输有关它的信息。 SharedArrayBuffers不能像ArrayBuffers那样分离。

目的和用途领域

类型化数组可以存储特定的数值并且速度很快。位图是类型化数组的典型候选者(例如画布2D / WebGL)。

Web工作者内部数据的大量数据处理是另一种用途,等等。我已经提到了客户端和服务器或文件系统之间的二进制传输。

DataViews非常适合解析或构建二进制文件和文件格式。

类型化数组是打包二进制数据以便通过网络发送到服务器或通过Web套接字以及WebRTC数据通道等方式的绝佳方式。

如果您处理音频,视频,画布或媒体录制,通常无法使用类型化数组。

使用类型化数组的关键是性能和内存。它们最常用于特殊场景,但在普通情况下只需存储数值(或utf-8字符串,加密向量等)时使用它们并没有错。它们速度快,内存占用少。

注意事项

需要注意以下几项预防措施:

字节顺序

必须对字节顺序采取一些预防措施。类型化数组总是反映它们运行的​​CPU架构,即。 little-endian或big-endian。大多数消费者系统都是小端的,但在使用* int16和* int32数组时,必须特别注意字节顺序。 DataView也可以帮助这个部分,但如果性能很重要,并不总是一个好的选择。

从服务器接收数据时,字节顺序也很重要。它们通常始终采用大端格式(AKA"网络顺序")。对于解析文件格式,同样适用。

浮点数编码

Float32 / Float64将读取和写入以IEEE-754格式编码的数字。如果多个视图用于同一个缓冲区,也需要注意这一点。

跨浏览器支持

现在

Most browsers supports typed arrays。如果您必须处理旧版浏览器,则必须返回IE9或更早版本的移动浏览器才能使用它们。

Safari在性能方面没有特别优化,但其他好处还有。版本5.1不支持Float64。

移动设备有自己的硬件限制,但一般来说:打字阵列可以安全使用。对于特殊情况,存在polyfill