实现JavaScript流式下载

Stream API

Stream API 允许 JavaScript 以编程方式访问从网络接收的数据流,并且允许开发人员根据需要处理它们。

概念和用法

JavaScript流式下载能够将大文件分块下载,减少内存占用,并提供更好的用户体验。流会将你想要从网络接受的资源分成一个个小的分块,然后按位处理它。

浏览器流式 API

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 选项可以设置一个较长的超时时间,来处理一些大文件/慢网络的下载场景

对于不同类型的文件,需要设置对应的 Content-Type

  • PDF: application/pdf
  • MS Word docx: application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • Excel xlsx: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • PowerPoint pptx: application/vnd.openxmlformats-officedocument.presentationml.presentation
  • JPEG 图像: image/jpeg
  • PNG 图像: image/png
  • GIF 图像: image/gif
  • BMP 图像: image/bmp
  • SVG 图像: image/svg+xml
  • MP3 音频: audio/mpeg
  • WAV 音频: audio/wav
  • MP4 视频: video/mp4
  • WebM 视频: video/webm
  • Zip 压缩包: application/zip
  • Rar压缩包: application/x-rar-compressed
  • Json: application/json
  • Javascript: application/javascript
  • Text: text/plain
  • Html: text/html
  • Xml: application/xml

这覆盖了大部分常见文件类型。不过有些文件的 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()方法创建一个临时的下载链接。然后,通过创建一个隐藏的<a>元素,并设置其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); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值