| 类 | 描述 |
|---|---|
TypedArray | 一组类提供类似数组的接口,用于交互处理二进制数据。包括 Uint8Array、Uint16Array、Int8Array 等。 |
Buffer | Uint8Array 的子类,实现了多种便捷方法。与本表中的其他元素不同,这是一个 Node.js API(Bun 也实现了它)。在浏览器中不能使用。 |
DataView | 提供 get/set 接口,可在特定字节偏移量处读写 ArrayBuffer 中的若干字节。常用于读写二进制协议。 |
Blob | 通常表示文件的只读二进制数据块。具有 MIME 类型 type、大小 size,以及转换为 ArrayBuffer、ReadableStream 和字符串的方法。 |
File | Blob 的子类,表示文件。具有 name 和 lastModified 时间戳。Node.js 20 中支持实验性实现。 |
BunFile | 仅在 Bun 中。Blob 的子类,表示懒加载的磁盘文件。通过 Bun.file(path) 创建。 |
ArrayBuffer 和视图
直到 2009 年,JavaScript 中没有原生语言机制来存储和操作二进制数据。ECMAScript v5 引入了一系列新的机制,最基础的构建块是 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 也不是全局定义的。可以将其看作接口或抽象类。ArrayBuffer 是字节序列,这些类型化数组类会按固定字节大小将字节解释为数字数组。
下表列出了类型化数组类,以及它们如何解读 ArrayBuffer 的字节。
| 类 | 描述 |
|---|---|
Uint8Array | 每 1 字节被解释为无符号 8 位整数。范围是 0 到 255。 |
Uint16Array | 每 2 字节被解释为无符号 16 位整数。范围是 0 到 65535。 |
Uint32Array | 每 4 字节被解释为无符号 32 位整数。范围是 0 到 4294967295。 |
Int8Array | 每 1 字节被解释为有符号 8 位整数。范围是 -128 到 127。 |
Int16Array | 每 2 字节被解释为有符号 16 位整数。范围是 -32768 到 32767。 |
Int32Array | 每 4 字节被解释为有符号 32 位整数。范围是 -2147483648 到 2147483647。 |
Float16Array | 每 2 字节被解释为 16 位浮点数。范围约为 -6.104e5 到 6.55e4。 |
Float32Array | 每 4 字节被解释为 32 位浮点数。范围约为 -3.4e38 到 3.4e38。 |
Float64Array | 每 8 字节被解释为 64 位浮点数。范围约为 -1.7e308 到 1.7e308。 |
BigInt64Array | 每 8 字节被解释为有符号 BigInt。范围 -9223372036854775808 到 9223372036854775807(但 BigInt 实际上能表示更大数)。 |
BigUint64Array | 每 8 字节被解释为无符号 BigInt。范围 0 到 18446744073709551615(但 BigInt 实际上能表示更大数)。 |
Uint8ClampedArray | 与 Uint8Array 相同,但赋值时会自动“钳制”元素值至 0-255 区间。 |
ArrayBuffer 字节时的字节解释方式:
| 字节 0 | 字节 1 | 字节 2 | 字节 3 | 字节 4 | 字节 5 | 字节 6 | 字节 7 | |
|---|---|---|---|---|---|---|---|---|
ArrayBuffer | 00000000 | 00000001 | 00000010 | 00000011 | 00000100 | 00000101 | 00000110 | 00000111 |
Uint8Array | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Uint16Array | 256 (1*256 + 0) | 770 (3*256 + 2) | 1284 (5*256 + 4) | 1798 (7*256 + 6) | ||||
Uint32Array | 50462976 | 117835012 | ||||||
BigUint64Array | 506097522914230528n |
ArrayBuffer 创建类型化数组:
ArrayBuffer 创建 Uint32Array,将报错。
Uint32 值需要 4 个字节(32 位)。因为 ArrayBuffer 长 10 字节,无法整除为 4 字节块。
解决方法是对 ArrayBuffer 的特定“切片”创建类型化数组。下面的 Uint16Array 只“视图”底层 ArrayBuffer 的 前 8 字节。我们指定字节偏移量为 0,长度为 2,表示数组包含两个 Uint32 元素。
ArrayBuffer,可以直接指定长度创建类型化数组:
push 和 pop(因为需要调整底层 ArrayBuffer 大小)。
Uint8Array
特别需要强调的是 Uint8Array,它表示经典的“字节数组”——一组范围在 0 到 255 之间的无符号 8 位整数。这是 JavaScript 中最常见的类型化数组。
在 Bun 中(未来可能其他 JavaScript 引擎也会),它带有在字节数组和经过序列化的 base64 或十六进制字符串之间转换的方法。
TextEncoder#encode 的返回类型,也是 TextDecoder#decode 的输入类型,这两个工具类设计用于字符串和各种二进制编码相互转换,尤其是 "utf-8"。
Buffer
Bun 实现了 Node.js 的 Buffer,这是一个在 JavaScript 标准中引入类型化数组之前用于操作二进制数据的 API。现在它已重新实现为 Uint8Array 子类,提供多种方法,包括数组方法和类似 DataView 的方法。
Blob
Blob 是 Web API,常用于表示文件。Blob 最初仅在浏览器实现(与 ArrayBuffer 不同,后者是 JavaScript 的一部分),但现已支持 Node 和 Bun。
通常不会直接创建 Blob 实例,更多情况下会从外部来源(例如浏览器中的 <input type="file"> 元素)或库接收 Blob 实例。但也可以通过一个或多个字符串或二进制“blob part”创建 Blob。
string,ArrayBuffer,TypedArray,DataView,或其他 Blob 实例。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 存储了类型化数组等二进制结构的底层数据,以下代码不是 转换 ArrayBuffer,而是用底层数据 创建 新实例。
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8 编码:转为数字数组 (number[])
转为 Blob
转为 ReadableStream
以下示例创建一个 ReadableStream,并将整个 ArrayBuffer 作为一个 chunk 入队。
分块读取
分块读取
要分块流式传输
ArrayBuffer,使用 Uint8Array 视图并逐块入队。从 TypedArray
转为 ArrayBuffer
获取底层 ArrayBuffer。注意,类型化数组可能是底层缓冲区的 部分 视图,因此大小可能不同。
转为 DataView
创建覆盖相同字节范围的 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
Blob 提供了便捷方法。
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8:转为数字数组 (number[])
转为 ReadableStream
从 ReadableStream
常用 Response 作为中间体,方便将 ReadableStream 转为其他格式。
ReadableStream 转换成多种二进制格式。
转为 ArrayBuffer
转为 Uint8Array
转为 TypedArray
转为 DataView
转为 Buffer
转为字符串
按 UTF-8:转为数字数组 (number[])
ReadableStream 为其块数组的工具。每个块可能是字符串、类型化数组或 ArrayBuffer。
转为 Blob
转为 ReadableStream
要将一个 ReadableStream 分割为两个可独立消费的流: