我正在从Node.js迁移到浏览器环境,但我仍然对ArrayBuffer和类型化数组(如Uint 8Array)感到困惑。
我很困惑在哪里使用类型化数组,在哪里直接使用ArrayBuffer。将一个转换成另一个并不难,反之亦然,但是在什么时候使用哪一个呢?
例如,当我在代码中创建一个表示数据块的对象时,它应该是ArrayBuffer还是Uint 8Array?它依赖于什么?
或者:我应该从我的函数返回ArrayBuffer
(例如,对于外部API),还是类型化数组?
请注意,我可以搜索如何准确地将元素等添加到这些类型化数组中;我所缺少的是一些简短的通用指南,在哪里使用什么。特别是当从节点的缓冲区移动。
2条答案
按热度按时间qhhrdooz1#
概念
ArrayBuffer s表示物理内存中的字节数组。ArrayBuffer是字节的实际存储,但很少直接使用-事实上,你没有权限直接读取ArrayBuffer的内容,只能为它传递一个引用。另一方面,它们用于服务器和客户端之间的二进制数据传输,或通过Blob从用户的文件系统传输。
要读取ArrayBuffer的内容,您需要使用 view。它位于顶部,并提供了一个“api”来访问不同宽度类型的字节,或任意访问。
宽度相关视图
根据您的需要使用不同的视图。如果您只需要读取字节值,即-128到127之间的有符号值或0到255之间的无符号值,您可以使用Int 8Array或Uint 8Array。请注意,它们的名称有点“误导”,因为它们是视图而不是数组,并且只引用底层的ArrayBuffer。
同样地,您也有Int8Array、Uint8Array、Uint8ClampedArray、Int16Array、Uint16Array、Int32Array、Uint3Array、Float32Array和Float64Array的检视。
除了 * int 8Arrays之外,其他视图都对ArrayBuffer的大小有一定的要求。例如,Uint 32Array视图必须位于可被4整除的ArrayBuffer之上,否则会引发错误。int 16视图需要两个字节的边界。
这通常不是问题,因为您可以直接使用视图的构造函数指定索引的数量,并且将自动为它创建一个匹配的ArrayBuffer来满足这些要求。
由于ArrayBuffer是一个字节数组,因此 * int 16视图从中读取两个字节-或者,一个索引=两个字节, int 32为四个,或者一个索引=四个字节,依此类推。
Uint 8Array和Uint 8 ClampedArray之间的主要区别是,超出范围的值将对普通数组进行模运算(例如256变为0)。在clamped数组中,值将按照建议进行箝位(256变为255)。
DataView提供灵活性
然后是DataView。它适用于需要灵活的ArrayBuffer并且需要从缓冲区中的位置读取可变宽度的情况,这些位置不一定是宽度或内存对齐的。
例如,* int 32索引将始终指向可被4整除的内存位置。另一方面,DataView可以从位置5读取Uint 32,并将在内部处理所有需要的步骤(位移位、掩码等),但代价是开销很小。
另一个不同之处是,DataView不使用索引,而是使用它所表示的数据的绝对字节位置,并且它自带了从任何位置读取或向任何位置写入各种宽度的方法。
x1c4d 1x指令集
在其他情况下,可以使用引用同一基础ArrayBuffer的多个不同视图。
目前没有整数的64位视图,但似乎是proposed for ES8。
共享数组缓冲区
提到可跨Web工作者使用的新SharedArrayBuffers也很有用。
在过去的一些浏览器中,你可以(现在仍然可以)使用transferable objects,但是SharedArrayBuffers在内存保持不变的意义上更有效,只传输关于它的信息。SharedArrayBuffers不能像ArrayBuffers那样分离。
用途和使用领域
类型化数组很适合存储特定的数值并且速度很快。位图是类型化数组的典型候选对象(例如canvas 2D/WebGL)。
Web worker内部的大量数据处理是另一个用途,我已经提到了客户端和服务器或文件系统之间的二进制传输。
DataView非常适合解析或构建二进制文件和文件格式。
类型化数组是打包二进制数据以便通过网络发送到服务器或通过Web套接字和WebRTC的数据通道之类的东西的一种很好的方式。
如果处理音频、视频、画布或媒体录制,通常无法使用类型化数组。
使用类型化数组的关键是性能和内存。它们最常用于特殊情况,但在普通情况下,当你只需要存储数值(或utf-8字符串,加密向量等)时,使用它们也没有什么错。它们速度快,内存占用少。
注意事项
有几个注意事项需要注意:
字节顺序
必须对字节顺序采取一些预防措施。类型化数组始终反映它们运行时所处的CPU体系结构,即little-endian或big-endian。大多数使用者系统都是little-endian,但在使用 * int 16和 * int 32数组时,必须特别注意字节顺序。DataView也可以帮助解决这一问题,但如果性能很重要,则DataView并不总是一个好选择。
从服务器接收数据时,字节顺序也很重要。它们通常都是big-endian格式(AKA“网络顺序”)。解析文件格式时也是如此。
浮点数编码
Float 32/Float 64将读取和写入以IEEE-754编码的数字。如果几个视图用于同一个缓冲区,也需要注意这一点。
跨浏览器支持
现在大多数浏览器都支持类型化数组。如果你必须处理旧的浏览器,你必须回到IE9或旧的移动的浏览器才能不能使用它们。
Safari在性能方面并没有特别优化,但其他好处还是有的。5. 1版本不支持Float 64。
移动的设备有其自身的硬件限制,但一般而言:类型化数组是可以安全使用的。对于特殊情况,存在polyfill。
yv5phkfx2#
我更喜欢在函数参数和返回类型中使用TypedArray。TypedArray可以表示ArrayBuffer的一个部分视图,这意味着它可能与底层缓冲区的大小不同。例如:
数据的部分视图是函数的关注点,而不是整个底层缓冲区。
如果在这种情况下选择将ArrayBuffer传递到函数中会怎么样呢?然后必须创建一个新的ArrayBuffer,这是复杂的并且对性能有害的:
但是,如果您使用TypedArray,当您想将字节写入存储(如indexedDB)时要小心。确保TypedArray与底层缓冲区对齐,否则您可能会将整个数据写入存储。
如果愿意,您也可以选择同时接受ArrayBuffer和TypedArray: