FileReader

FileReader用于从 Blob 中读取实际可供 JavaScript 语言处理的数据。FileReader 出现于 ES5 时代,因此它的异步操作是基于事件回调的,而不是更现代化的 Promise。

FileReader 的总体使用方式可以总结如下:

  1. 创建 FileReader 对象
  2. 订阅 FileReader 对象的事件并作相应处理
    • loadstart事件表示开始读取
    • progress事件用于反馈当前读取进度,对于较大的数据,可以根据事件数据向用于展示进度
    • loadend事件表示读取结束,无论最终是成功还是失败
    • load事件表示已经成功读取,可以通过fileReader.result获取读到的数据,不同的读取方法会得到不同类型的数据
    • error事件表示读取过程中发生错误,也可以通过fileReader.error获取发生的错误
  3. 执行读取操作,等待之前订阅的事件触发
    • readAsArrayBuffer(blob)方法将 Blob 内容读取为 ArrayBuffer
    • readAsText(blob[, encoding])方法将 Blob 内容读取为 string
    • readAsDataURL(blob)方法将 Blob 内容读取为data:格式的内容内嵌的 URL

示例:读取 Blob 中的文本

我们将构造一个包含文本的 Blob,然后通过readAsText()将其读出。

const blob = new Blob(["hello world!"], { type: "text/plain" });

const reader = new FileReader();
reader.addEventListener("load", function () {
  console.log("got text:", this.result);
});
reader.readAsText(blob);

readyState状态机

FileReader 对象的readyState属性指示当前的读取状态在哪一阶段,可能的值有:

readyState描述
FileReader.EMPTY0尚未读取任何内容
FileReader.LOADING1正在读取
FileReader.DONE2所有内容都已读取完成

让我们尝试订阅状态变更事件,并打印出readyState的值:

const blob = new Blob(["hello world!"], { type: "text/plain" });

function onEventFired(e) {
  console.log(`event: ${e.type}, ready state: ${this.readyState}`);
}

const reader = new FileReader();
console.log(`ready state: ${reader.readyState}`);
reader.addEventListener("loadstart", onEventFired);
reader.addEventListener("progress", onEventFired);
reader.addEventListener("loadend", onEventFired);
reader.addEventListener("load", onEventFired);
reader.readAsText(blob);

执行后输出:

ready state: 0
event: loadstart, ready state: 1
event: progress, ready state: 1
event: load, ready state: 2
event: loadend, ready state: 2

进度与终止

如要读取的 Blob 数据量较大,可能需要向用户展示进度信息,progress事件可用于此类目的。

而在读取过程中不再需要继续读取时(例如用户取消),可以调用abort()方法,此时,也会触发 abort事件。

const blob = new Blob([new ArrayBuffer(1024 ** 3)]);

const reader = new FileReader();
const eventHandler = e => {
  console.log(`event: ${e.type}, progress: ${e.loaded} / ${e.total}`);
};
reader.addEventListener("progress", eventHandler);
reader.addEventListener("abort", eventHandler);

let count = 0;
reader.addEventListener("progress", function () {
  count++;
  if (count == 2) this.abort();
});
reader.readAsArrayBuffer(blob);

执行后输出:

event: progress, progress: 212795392 / 1073741824
event: progress, progress: 402653184 / 1073741824
event: abort, progress: 0 / 0