Stream API 允许 JavaScript 以编程方式访问从网络接收的数据流,并且允许开发人员根据需要处理它们。
JavaScript流式下载能够将大文件分块下载,减少内存占用,并提供更好的用户体验。流会将你想要从网络接受的资源分成一个个小的分块,然后按位处理它。
Streams API
是浏览器提供给 JS 的流式操作数据的接口。
其中包含有两个主要的接口:可读流、可写流
可读流 ReadableStream
表示数据的可读流。用于处理 Fetch API 返回的响应,或者开发者自定义的流(例如通过 ReadableStream() 构造的流
可写流 WritableStream
为将流写入目的地(称为接收器)的过程,提供了一个标准抽象。内置了背压和队列机制
其他 API 扩展 Response.body
一个成功的 fetch request 响应体会默认暴露为 ReadableStream,从而可以采用相应的 reader 来处理等
ReadableStream 接口的 pipeTo() 方法通过管道将当前的 ReadableStream 中的数据传递给给定的 WritableStream 并且返回一个 Promise,promise 在传输成功完成时兑现,在遇到任何错误时则会被拒绝。
传输一个流时通常会在传输的持续时间内锁定这个流,以阻止其他 reader 锁定它。
最最最简单的示列
// npm install --save streamsaver
// import 'streamsaver'; //main.js
import { createWriteStream } from 'streamsaver';
// 这里的 URL 可以是文件下载地址,也可以是文件流
const response = await fetch(url, {
method: 'get',
timeout: Infinity, // 表示无限等待
responseType: 'blob'
});
const readableStream = response.body;
pipeStreamToFile(readableStream, filename);
// 创建一个文件写入流
async function pipeStreamToFile(readableStream, fileName) {
const writableStream = createWriteStream(fileName);
return new Promise((resolve, reject) => {
readableStream.pipeTo(writableStream)
.then(() => {
resolve();
})
.catch(err => {
reject(err);
});
});
}
在 fetch 请求中可以通过设置 timeout 选项来指定超时时间,单位为毫秒
如果想设置一个很长的超时时间,例如 10 分钟,可以timeout: 1000 * 60 * 10
这里超时时间是 1000 毫秒 x 60 秒 x 10 分钟 = 600,000 毫秒。
为了代码可读性,可以提取出一个常量
// 10分钟的毫秒数
const TEN_MINUTES = 1000 * 60 * 10;
fetch(url, {
timeout: TEN_MINUTES
});
timeout 选项可以设置一个较长的超时时间,来处理一些大文件/慢网络的下载场景
这覆盖了大部分常见文件类型。不过有些文件的 MIME 类型比较复杂,需要查阅开发文档才能得到准确的 MIME 类型字符串。
设置正确的 Content-Type 非常重要,以确保文件能被客户端正确处理。
注意点 ⚠️
大多数浏览器都有一个默认的最大同时下载文件数限制,通常为6个到10个文件。这是为了避免大量同时下载文件导致网络拥堵和浏览器卡顿的情况发生
如果做批量下载文件的话 要考虑浏览器的并发 以及默认的最大同时下载文件数限制
If you need to save really large files bigger than the blob’s size limitation or don’t have enough RAM, then have a look at the more advanced StreamSaver.js
一般这种下载文件的方式 2 个 G
的文件 浏览器就会崩
当用户点击下载链接时,浏览器会生成一个Blob
对象,并使用URL.createObjectURL()
方法创建一个临时的下载链接。然后,通过创建一个隐藏的元素,并设置其
href
为临时链接,download
属性为指定的文件名,来触发下载。最后,我们通过调用URL.revokeObjectURL()
释放临时链接,避免内存泄漏。
请求的时候规范 responseType = 'blob' 或者在下面转换
const blob = new Blob([res], { type: 'Content-Type ');
const fileName = title + '.后缀';
const elink = document.createElement('a'); // 创建a标签
elink.download = fileName; // 为a标签添加download属性 下载名称
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click(); // 点击下载
URL.revokeObjectURL(elink.href); // 释放URL 对象
document.body.removeChild(elink);