顾名思义,FileReaderSync 类型就是 FileReader 的同步版本。这个类型拥有与 FileReader 相同的方法,只有在整个文件都加载到内存之后才会继续执行。FileReaderSync 只在工作线程中可用, 因为如果读取整个文件耗时太长则会影响全局。
假设通过 postMessage()向工作线程发送了一个 File 对象。以下代码会让工作线程同步将文件 读取到内存中,然后将文件的数据 URL 发回来:
// worker.js
self.omessage = (messageEvent) => {
const syncReader = new FileReaderSync(); console.log(syncReader); // FileReaderSync {}
// 读取文件时阻塞工作线程
const result = syncReader.readAsDataUrl(messageEvent.data);
// PDF 文件的示例响应
console.log(result); // data:application/pdf;base64,JVBERi0xLjQK...
// 把URL发回去
self.postMessage(result);
};
Blob与部分读取
某些情况下,可能需要读取部分文件而不是整个文件。为此,File 对象提供了一个名为 slice() 的方法。slice()方法接收两个参数:起始字节和要读取的字节数。这个方法返回一个 Blob 的实例, 而 Blob 实际上是 File 的超类。
blob 表示二进制大对象(binary larget object),是 JavaScript 对不可修改二进制数据的封装类型。包 含字符串的数组、ArrayBuffers、ArrayBufferViews,甚至其他 Blob 都可以用来创建 blob。Blob 构造函数可以接收一个 options 参数,并在其中指定 MIME 类型:
console.log(new Blob(['foo']));
// Blob {size: 3, type: ""}
console.log(new Blob(['{"a": "b"}'], { type: 'application/json' })); // {size: 10, type: "application/json"}
console.log(new Blob(['<p>Foo</p>', '<p>Bar</p>'], { type: 'text/html' })); // {size: 20, type: "text/html"}
Blob 对象有一个 size 属性和一个 type 属性,还有一个 slice()方法用于进一步切分数据。另 外也可以使用 FileReader 从 Blob 中读取数据。下面的例子只会读取文件的前 32 字节:
reader = new FileReader(),
blob = blobSlice(files[0], 0, 32);
if (blob) {
reader.readAsText(blob);
reader.onerror = function() {
output.innerHTML = "Could not read file, error code is " +
reader.error.code;
};
reader.onload = function() {
output.innerHTML = reader.result;
};
let filesList = document.getElementById("files-list");
filesList.addEventListener("change", (event) => {
let info = "", 18 output = document.getElementById("output"),
progress = document.getElementById("progress"),
files = event.target.files,
} else {
console.log("Your browser doesn't support slice()."); 22
} });
只读取部分文件可以节省时间,特别是在只需要数据特定部分比如文件头的时候。
对象 URL 有时候也称作 Blob URL,是指引用存储在 File 或 Blob 中数据的 URL。对象 URL 的优 24 点是不用把文件内容读取到 JavaScript 也可以使用文件。只要在适当位置提供对象 URL 即可。要创建对
象 URL,可以使用 window.URL.createObjectURL()方法并传入 File 或 Blob 对象。这个函数返回 的值是一个指向内存中地址的字符串。因为这个字符串是 URL,所以可以在 DOM 中直接使用。例如, 以下代码使用对象 URL 在页面中显示了一张图片:
let filesList = document.getElementById("files-list"); filesList.addEventListener("change", (event) => { 26
let info = "",
output = document.getElementById("output"), progress = document.getElementById("progress"), files = event.target.files,
reader = new FileReader(),
url = window.URL.createObjectURL(files[0]);
if (url) {
if (/image/.test(files[0].type)) {
output.innerHTML = `<img src="${url}">`;
} else {
output.innerHTML = "Not an image.";
}
} else {
output.innerHTML = "Your browser doesn't support object URLs.";
}
});
如果把对象 URL 直接放到标签,就不需要把数据先读到 JavaScript 中了。标签可以直 接从相应的内存位置把数据读取到页面上。
使用完数据之后,最好能释放与之关联的内存。只要对象 URL 在使用中,就不能释放内存。如果 想表明不再使用某个对象 URL,则可以把它传给 window.URL.revokeObjectURL()。页面卸载时, 所有对象 URL 占用的内存都会被释放。不过,最好在不使用时就立即释放内存,以便尽可能保持页面 占用最少资源。