概念
ArrayBuffers代表物理内存中的字节数组。ArrayBuffer是字节的实际存储位置,但很少直接使用它 - 实际上,您无法直接访问ArrayBuffer的内容,只能传递一个引用。另一方面,它们用于服务器和客户端之间的二进制数据传输,或者通过Blob从用户的文件系统传输。
![内存中的ArrayBuffer字节数组](https://istack.dev59.com/AmCNE.webp)
内存中的ArrayBuffer字节数组 - 每个索引等于一个字节。ArrayBuffer在内存中对齐。
要读取ArrayBuffer的内容,您需要使用一个视图。它位于顶部,并提供了一个“api”来按不同宽度类型或任意方式访问字节。
宽度相关的视图
根据您的需求,可以使用不同的视图。如果您只需要读取字节值,即介于-128和127之间的有符号值或介于0和255之间的无符号值,则应使用Int8Array或Uint8Array。请注意,它们的名称有点“误导”,因为它们是视图而不是数组,并且仅引用底层的ArrayBuffer。
同样,您可以查看
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array和
Float64Array的视图。
除了*int8Arrays之外,其他的都对ArrayBuffer大小有一些要求。例如,Uint32Array视图必须位于一个可被四整除的ArrayBuffer上,否则会抛出错误。*int16视图需要两字节边界。
通常这不是个问题,因为你可以直接使用视图的构造函数指定索引的数量,并且会自动为它创建一个匹配的ArrayBuffer来满足这些要求。
由于ArrayBuffer是一个字节数组,*int16视图从中读取两个字节 - 或者说一个索引等于两个字节,*int32等于四个字节,依此类推。
Uint8Array和Uint8ClampedArray之间的主要区别在于超出范围的值在普通数组中会进行模运算(例如256变成0),而在夹紧数组中,这些值会被夹紧(256变成255)。
*int16视图
![*int32视图](https://istack.dev59.com/xoqzg.webp)
Int32/Uint32和Float32视图-每个索引代表四个字节,并且内存对齐。
![Float64视图](https://istack.dev59.com/h8EZ7.webp)
Float64视图-每个索引代表八个字节,并且内存对齐。
灵活性的DataView
然后是DataView。这适用于需要灵活的ArrayBuffer并且需要从缓冲区中读取可变宽度和位置的场景,这些位置不一定是宽度或内存对齐的。
例如,*int32索引将始终指向可以被四整除的内存位置。另一方面,DataView可以从位置5读取一个Uint32,并在内部处理所有所需的步骤(位移、掩码等),但会带来一点额外开销。
另一个区别是DataView不使用索引,而是使用绝对字节位置来表示其所代表的数据,并且它具有自己的方法来从任意位置读取或写入各种宽度的数据。
![DataView](https://istack.dev59.com/mxjI0.webp)
DataView - 可以从任何位置和任何宽度读取。
在其他情况下,您可以使用几个不同的视图引用相同的底层ArrayBuffer。
目前还没有64位整数的视图,但似乎已提议用于ES8。
SharedArrayBuffers
还有一个有用的新功能SharedArrayBuffers,可以在Web Workers之间使用。
过去在某些浏览器中可以使用可传递对象,但SharedArrayBuffers在内存保持不变的意义上更高效,只是关于它的信息被传输。SharedArrayBuffers不能像ArrayBuffers一样分离。
目的和使用领域
类型化数组适合存储特定的数字值,并且速度快。位图是类型化数组的典型候选(例如canvas 2D/WebGL)。
在Web Workers内部进行大量数据处理是另一种用途等等。我已经提到过客户端和服务器之间的二进制传输或文件系统。
DataViews非常适合解析或构建二进制文件和文件格式。
Typed arrays是将二进制数据打包发送到网络、服务器或通过Web套接字和WebRTC的数据通道的绝佳方式。
如果你处理音频、视频、画布或媒体录制,往往无法避免使用Typed arrays。
使用Typed arrays的关键是性能和内存。它们通常在特殊场景中使用,但在普通情况下只需要存储数值(或utf-8字符串、加密向量等)时,也没有问题。它们速度快,占用内存少。
注意事项
有几个注意事项需要注意:
字节顺序
在字节顺序方面必须注意一些预防措施。Typed arrays始终反映它们运行的CPU架构,即小端或大端。大多数消费者系统都是小端,但当使用*int16和*int32数组时,必须特别注意字节顺序。DataView在这方面也可以提供帮助,但如果性能很重要,它并不总是一个好选择。
字节顺序在接收来自服务器的数据时也很重要。它们通常以大端格式(也称为“网络顺序”)存在。对于解析文件格式,同样适用。
浮点数编码
Float32/Float64 将读取和写入使用 IEEE-754 格式编码的数字。如果对同一缓冲区使用了多个视图,这也是需要注意的事项。
跨浏览器支持
现在大多数浏览器都支持类型化数组。如果您必须处理旧版浏览器,那么只有回退到 IE9 或更早版本的移动浏览器才无法使用它们。
Safari 在性能方面并不特别优化,但其他好处还是有的。5.1 版本不支持 Float64。
移动设备有其自身的硬件限制,但通常而言:类型化数组是安全可用的。对于特殊情况,存在一个polyfill。
var buffer = new ArrayBuffer(8)
,就像链接中的文档中所示。 - Karel BílekArrayBuffer
(例如,对于外部API),还是返回类型化数组? - Karel Bílek