Skip to content

ArrayBuffer 与 Blob

ArrayBuffer 对象

简介

ArrayBuffer 对象表示一段二进制数据,用来模拟内存里面的数据。通过这个对象,JavaScript 可以读写二进制数据,可以看作内存数据的表达。这个对象是 ES6 才写入标准的。

浏览器原生提供ArrayBuffer()构造函数,用来生成实例。它接受一个整数作为参数,表示这段二进制数据占用多少个字节。

const buffer = new ArrayBuffer(8);

上面代码中,实例对象buffer占用8个字节。

ArrayBuffer 对象有实例属性byteLength,表示当前实例占用的内存长度(单位字节)。

ArrayBuffer 对象有实例方法slice(),用来复制一部分内存。它接受两个整数参数,分别表示复制的开始位置(从0开始)和结束位置(复制时不包括结束位置),如果省略第二个参数,则表示一直复制到结束。

  1. var buf1 = new ArrayBuffer(8);
  2. var buf2 = buf1.slice(0);

上面代码表示复制原来的实例。

TypedArray

TypedArray 对象代表了格式化的二进制数据,它们是 ArrayBuffer 的视图。由于 ArrayBuffer 本身只是一段内存,无法直接读写其中的内容。TypedArray 扮演着“翻译官”的角色,它将 ArrayBuffer 中的原始二进制数据转换成特定类型(如 8 位整数、32 位浮点数等)的数组,可以方便地进行操作和查看数据。

类型

JavaScript 提供了多种 TypedArray,每种都对应一种特定的数据类型,例如:

  • Int8Array:8 位有符号整数
  • Uint8Array:8 位无符号整数
  • Int16Array:16 位有符号整数
  • Uint16Array:16 位无符号整数
  • Int32Array:32 位有符号整数
  • Uint32Array:32 位无符号整数
  • Float32Array:32 位浮点数
  • Float64Array:64 位浮点数

操作

创建一个 TypedArray 实例时,它会自动在内部创建一个 ArrayBuffer。例如:

js
// 创建一个包含 16 个 32 位整数的 TypedArray
const int32View = new Int32Array(16);

也可以在一个已有的 ArrayBuffer 之上创建一个 TypedArray,可以用不同的视角去查看同一块内存。

js
// 创建一个 8 字节的 ArrayBuffer
const buffer = new ArrayBuffer(8);

// 创建一个 Uint8Array 视图,将 buffer 看作 8 个 8 位无符号整数
const uint8View = new Uint8Array(buffer);
console.log(uint8View.length); // 8

// 创建一个 Uint16Array 视图,将 buffer 看作 4 个 16 位无符号整数
const uint16View = new Uint16Array(buffer);
console.log(uint16View.length); // 4

像操作普通数组一样来操作 TypedArray,包括读写值、遍历等。

js
// 创建一个 Int8Array,长度为 4
const int8View = new Int8Array(4);

// 写入数据
int8View[0] = 10;
int8View[1] = -20;

// 读取数据
console.log(int8View[0]); // 10
console.log(int8View[1]); // -20

// 遍历
for (const value of int8View) {
  console.log(value);
}

当通过 TypedArray 写入数据时,如果数值超出其类型所能表示的范围,会自动进行截断处理。例如,一个 Int8Array 只能存储 -128 到 127 之间的整数,如果写入 256,它会被截断为 0。

应用场景

  • 处理二进制数据:在处理文件、图像、音频或网络数据时,TypedArray 是必不可少的。它能够高效地读取和写入底层的二进制流。
  • WebGL 和 WebGPU:在图形编程中,TypedArray 用于存储顶点、颜色等大量数据,并将其传递给 GPU。
  • 性能优化:当处理大型数值数据集时,TypedArray 的性能通常优于普通 JavaScript 数组。
  • 共享内存:在多线程(如 Web Workers)环境中,TypedArray 可以与 SharedArrayBuffer 配合,实现不同线程间高效的数据共享。

Blob 对象

简介

Blob 对象表示一个不可变、原始数据的类文件对象。它通常用来处理文件,它的名字是 Binary Large Object(二进制大型对象)的缩写。它与 ArrayBuffer 的区别在于,它用于操作二进制文件,而 ArrayBuffer 用于操作内存

浏览器原生提供Blob()构造函数,用来生成实例对象。

new Blob(array,options)

Blob构造函数接受两个参数。第一个参数是数组,成员是字符串或二进制对象,表示新生成的Blob实例对象的内容;第二个参数是可选的配置对象,目前只有一个属性type,表示数据的 MIME 类型,默认是空字符串。

实例属性和实例方法

Blob具有两个实例属性sizetype,分别返回数据的大小和类型。

js
var htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
var myBlob = new Blob(htmlFragment, {type : 'text/html'})
myBlob.size // 32
myBlob.type // "text/html"

实例方法:

  • arrayBuffer() 返回一个 Promise,会兑现一个包含 blob 二进制数据内容的 ArrayBuffer
  • bytes() 返回一个 Promise,会兑现为一个包含 blob 内容的字节数组的 Uint8Array
  • slice() 创建并返回一个新的 Blob 对象,该对象包含调用它的 blob 的子集中的数据。
  • text 返回 Promise,兑现一个包含 blob 内容的 UTF-8 格式的字符串。
  • stream 返回一个 ReadableStream对象,读取它将返回包含在 Blob 中的数据。

生成 URL

浏览器允许使用URL.createObjectURL()方法,针对 Blob 对象生成一个临时 URL,以便于某些 API 使用。这个 URL 以blob://开头,表明对应一个 Blob 对象,协议头后面是一个识别符,用来唯一对应内存里面的 Blob 对象。这一点与data://URL(URL 包含实际数据)和file://URL(本地文件系统里面的文件)都不一样。

File drag and drop HTML 拖放接口使得 web 应用能够在网页中拖放文件,下面的案例用了拖放接口。

html
<div style="background-color: grey; padding: 20px; text-align: center;" ondrop="dropHandler(event);"
	ondragover="dragOverHandler(event);">
	<p>Drag one or more files to this Drop Zone ...</p>
</div>

<script>
	function dragOverHandler(ev) {
		event.preventDefault()
	}

	function dropHandler(ev) {
		console.log("File(s) dropped", ev.dataTransfer.items);
		// 阻止浏览器默认行为 (打开文件)
		ev.preventDefault();

		if (ev.dataTransfer.items) {
			// 使用 DataTransfer.items
			for (var i = 0; i < ev.dataTransfer.items.length; i++) {
				// If dropped items aren't files, reject them
				if (ev.dataTransfer.items[i].kind === "file") {
					var file = ev.dataTransfer.items[i].getAsFile();
					console.log("111... file[" + i + "].name = " + file.name);
					var img = document.createElement('img');
					img.src = URL.createObjectURL(file);
					img.onload = function () {
						this.width = 100;
						document.body.appendChild(this);
						URL.revokeObjectURL(this.src);
					}
				}
			}
		} else {
			// 也可以使用 DataTransfe.files
			for (var i = 0; i < ev.dataTransfer.files.length; i++) {
				console.log(
					"222... file[" + i + "].name = " + ev.dataTransfer.files[i].name,
				);
			}
		}
	}
</script>

上面代码通过为拖放的图片文件生成一个 URL,产生它们的缩略图,从而使得用户可以预览选择的文件。

浏览器处理 Blob URL 就跟普通的 URL 一样,如果 Blob 对象不存在,返回404状态码;如果跨域请求,返回403状态码。Blob URL 只对 GET 请求有效,如果请求成功,返回200状态码。由于 Blob URL 就是普通 URL,因此可以下载。

文件操作

见下一节