ArrayBuffer 和视图
直到 ECMAScript v5(2009 年)引入了一系列机制之前,JavaScript 都没有语言原生的方式来存储和操作二进制数据。其中最基础的构建块是 ArrayBuffer,一种表示内存中字节序列的数据结构。
ArrayBuffer 中读取或写入值;你能做的只有检查其大小,以及从中创建“切片”。
ArrayBuffer 实例,并允许你读取和操作底层数据的类。视图有两种类型:_类型化数组_和 DataView。
DataView
DataView 类是一个底层接口,用来读取和操作 ArrayBuffer 中的数据。
以下代码创建一个 DataView,并将第一个字节设置为 3。
1 处写入一个 Uint16。这需要两个字节。值 513 等于 2 * 256 + 1;用字节表示就是 00000010 00000001。
ArrayBuffer 的前三个字节现在都有值。尽管第二个和第三个字节是通过 setUint16() 写入的,你仍然可以使用 getUint8() 读取每个组成字节。
ArrayBuffer 的可用空间,就会抛出错误。以下代码尝试在字节偏移量 0 处写入一个 Float64(需要 8 个字节),但该缓冲区的长度只有 4 个字节。
DataView 支持以下方法:
TypedArray
类型化数组是一组类,提供类似数组的接口,用于访问 ArrayBuffer 中的数据。与 DataView 可以在某个偏移量写入不同大小的数字不同,TypedArray 将底层字节解释为固定大小数字的数组。
通常会通过它们共同的超类
TypedArray 来统称这一系列类。这个类对于 JavaScript 来说是
内部的;你无法直接创建它的实例,并且 TypedArray 未定义在全局作用域中。可以将它视为一个
interface 或抽象类。ArrayBuffer 中的字节:
下面的表展示了用不同类型化数组类查看 ArrayBuffer 字节时的字节解释方式:
下面的表展示了不同类型化数组类如何解释 ArrayBuffer 中的相同字节。
从已有的 ArrayBuffer 创建类型化数组:
ArrayBuffer 实例化 Uint32Array 会抛出错误。
Uint32 值需要四个字节(32 位)。由于 ArrayBuffer 的长度为 10 个字节,因此无法将其内容整齐地划分为每组 4 个字节的数据块。
要解决此问题,请在 ArrayBuffer 的特定“切片”上创建类型化数组。下面的 Uint32Array 只“查看”底层 ArrayBuffer 的前 8 个字节:byteOffset 为 0,length 为 2,表示该数组所包含的 Uint32 值的数量。
ArrayBuffer 实例;可以直接将长度传递给类型化数组构造函数:
push 和 pop 不可用,因为它们需要调整底层 ArrayBuffer 的大小。
Uint8Array
Uint8Array 是 JavaScript 中最常见的类型化数组。它表示经典的“字节数组”:由一系列介于 0 到 255 之间的 8 位无符号整数组成。
在 Bun 中,它提供了在字节数组与其 base64 或十六进制字符串表示形式之间进行转换的方法。
TextEncoder#encode 的返回值,也是 TextDecoder#decode 的输入类型。这两个实用工具类用于在字符串与各种二进制编码之间进行转换,其中最重要的是 "utf-8"。
Buffer
Bun 实现了 Node.js 的 Buffer,这是一个在 JavaScript 标准中引入类型化数组之前用于操作二进制数据的 API。现在它已重新实现为 Uint8Array 子类,提供多种方法,包括数组方法和类似 DataView 的方法。
Blob
Blob 是一种通常用于表示文件的 Web API。它最初源自浏览器(不同于属于 JavaScript 本身的 ArrayBuffer),但 Node.js 和 Bun 也支持它。
你很少会直接创建 Blob 实例;它们通常来自外部来源(例如浏览器中的 <input type="file"> 元素)或某个库。不过,你可以使用一个或多个字符串或二进制“Blob 部分”创建 Blob。
string、ArrayBuffer、TypedArray、DataView 或其他 Blob 实例。这些部分会按照给定的顺序进行拼接。
Blob 的内容。
BunFile
BunFile 是 Blob 的子类,表示磁盘上延迟加载的文件。与 File 一样,它添加了 name 和 lastModified 属性。与 File 不同,它不要求将文件加载到内存中。
File
File 是 Blob 的子类,添加了 name 和 lastModified 属性。在浏览器中,它通常用于表示通过 <input type="file"> 元素上传的文件。Node.js 和 Bun 都实现了 File。
流
流让你能够处理二进制数据,而无需一次性将所有数据加载到内存中。它们通常用于读取和写入文件、发送和接收网络请求,以及处理大量数据。 Bun 实现了 Web API 中的ReadableStream 和 WritableStream。
要创建可读流:
for await 逐块读取流。
格式转换
使用本节作为将一种二进制格式转换为另一种格式的参考。从 ArrayBuffer
由于 ArrayBuffer 存储着其他二进制结构(如 TypedArray)所依赖的数据,以下代码片段并不是将 ArrayBuffer 转换 为另一种格式。相反,它们使用底层数据_创建_一个新实例。
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8 编码:转为数字数组(number[])
转为 Blob
转为 ReadableStream
以下示例创建一个 ReadableStream,并将整个 ArrayBuffer 作为一个 chunk 入队。
分块读取
分块读取
要分块流式传输
ArrayBuffer,使用 Uint8Array 视图并逐块入队。从 TypedArray
转为 ArrayBuffer
buffer 属性是底层的 ArrayBuffer。TypedArray 可以是该缓冲区某个_切片_的视图,因此两者的大小可能不同。
转为 DataView
要创建一个覆盖与 TypedArray 相同字节范围的 DataView:
转为 Buffer
转为字符串
按 UTF-8 编码:转为数字数组(number[])
转为 Blob
转为 ReadableStream
分块读取
分块读取
分块流式传输
ArrayBuffer,将类型化数组划分为多块,分别入队。从 DataView
转为 ArrayBuffer
转为 TypedArray
仅当 DataView 的 byteLength 是类型化数组元素字节大小的倍数时有效。
转为 Buffer
转为字符串
按 UTF-8 编码:转为数字数组(number[])
转为 Blob
转为 ReadableStream
分块读取
分块读取
分块流式传输
ArrayBuffer,将 DataView 划分为多块,逐块入队。从 Buffer
转为 ArrayBuffer
转为 TypedArray
转为 DataView
转为字符串
按 UTF-8:转为数字数组(number[])
转为 Blob
转为 ReadableStream
分块读取
分块读取
分块流式传输
ArrayBuffer,将 Buffer 划分多块,逐块入队。从 Blob
转为 ArrayBuffer
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8:转为数字数组(number[])
转为 ReadableStream
从 ReadableStream
Response 是将 ReadableStream 转换为其他格式时常用的中间类型。
ReadableStream 转换为各种二进制格式实现了经过优化的便捷函数。
转为 ArrayBuffer
转为 Uint8Array
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8:转为数字数组(number[])
ReadableStream 为其块数组的工具。每个块可能是字符串、类型化数组或 ArrayBuffer。
转为 Blob
转为 ReadableStream
要将一个 ReadableStream 分割为两个可独立消费的流: