在JavaScript中实现大文件的并发下载

Large file download flow

你可能已经知道上传大文件的解决方案了。在上传大文件时,为了提高上传效率,我们一般会使用Blob.slice方法将大文件切成若干块,并在所有块上传成功后通知服务器合并这些块。

那么对于大文件的下载,我们是否可以采用类似的思路呢?在服务器端支持Range请求头的条件下,我们也可以实现多线程的分块下载,如下图所示。

Large file download flow

看完上图,相信你对大文件下载的解决方案有了一定的了解。接下来,我们就从HTTP范围请求说起。

什么是HTTP范围请求?

HTTP范围请求允许服务器只向客户端发送HTTP消息的一部分。范围请求在传输大型媒体文件时很有用,或者与恢复文件下载功能结合使用。如果响应中存在Accept-Ranges头(其值不是 "无"),那么服务器就支持范围请求。

在一个范围标头内,可以一次请求多个部分,服务器将把它们作为一个多部分文件返回。如果服务器返回一个范围响应,则需要206部分内容状态代码。如果请求的范围无效,服务器将返回416 Range Not Satisfiable状态代码,表示客户端错误。允许服务器忽略Range头并返回整个文件,状态码为200。

范围语法

Range: <unit>=<range-start>-
复制代码
  • :指定范围的单位。这通常是字节。
  • :一个在给定单位中的整数,表示请求范围的开始。
  • :一个给定单位的整数,表示请求范围的结束。这个值是可选的,如果省略,文件的末尾将被视为范围的结束。

在了解了Range的语法后,让我们举几个例子。

单部分范围

$ curl 
复制代码

多部分范围

$ curl 
复制代码

这就是我们需要了解的关于HTTP范围请求的全部内容,所以让我们进入正题,开始介绍如何实现大文件下载。

如何实现大文件下载?

为了更好地理解下面的内容,让我们看一下整体的流程图。

Large file download flow chart

在了解了大文件下载的过程后,我们先来定义上述过程中涉及的一些辅助函数。

1.定义getContentLength函数

这个函数是用来获取文件的长度的。我们通过发送HEAD请求,然后从响应头中读取Content-Length信息,得到当前URL对应的文件的内容长度。

medium.com/media/233d5…

2.定义asyncPool函数

asyncPool函数用于实现异步任务的并发控制。该函数接受3个参数。

  • 并发性。并发限制数(>=1)
  • iterable。一个输入的可迭代对象,如String、Array、TypedArray、Map和Set。
  • iteratorFn。迭代器函数,需要两个参数:每次迭代的值和可迭代对象本身。迭代器函数应该返回一个承诺或者是一个异步函数。

medium.com/media/59e61…

3.定义getBinaryContent函数

getBinaryContent函数用于根据传递的参数发起一个范围请求,从而下载指定范围内的文件数据块。

medium.com/media/002c2…

注意ArrayBuffer对象是用来表示通用的、固定长度的原始二进制数据缓冲区的。我们不能直接操作ArrayBuffer的内容,而是通过TypedArray对象或DataView对象,以特定的格式表示缓冲区中的数据,并通过这些格式读写缓冲区的内容。

4.定义concatenate函数

由于ArrayBuffer对象不能直接操作,我们需要先将ArrayBuffer对象转换成Uint8Array对象,然后再进行合并操作。下面定义的concatenate函数就是用来合并下载的文件数据块的。具体代码如下。

medium.com/media/f4099…

5.定义saveAs函数

saveAs函数用于实现客户端的文件保存功能,这里只是一个简单的实现。在实际项目中,你可以考虑直接使用FileSaver.js

medium.com/media/edbea…

在saveAs函数中,我们使用了Blob和Object URL。其中Object URL是一个伪协议,允许Blob和File对象作为图片、下载二进制数据的链接等的URL来源。

在浏览器中,我们使用URL.createObjectURL方法来创建一个Object URL,它接收一个Blob对象,并以blob:/的形式为其创建一个唯一的URL。

相应的例子如下。

blob:
复制代码

浏览器在内部为每个通过URL.createObjectURL生成的URL存储了一个URL→Blob映射。因此,这样的URL比较短,但可以访问blob。生成的URL只有在当前文档打开的情况下才有效。

6.定义下载函数

下载函数用于执行下载操作,它支持3个参数。

  • url。资源的URL
  • chunkSize。块的大小,以字节为单位
  • poolLimit:限制并发的数量。

medium.com/media/a0e07…

7.大文件并发下载完整示例

使用上面定义的辅助函数,我们可以轻松实现大文件的并发下载。

concurrency download demo

完整的代码如下。

medium.com/media/85899…

本文介绍了如何使用JavaScript中的asyncPool函数来实现大文件的并发下载。它还描述了如何通过HEAD请求获得文件大小,如何发起HTTP范围请求,以及如何在客户端保存文件。

资源

位:建立更好的UI组件库

向你问好 比特.它是组件驱动的应用开发的第一大工具。

有了Bit,你可以将你的应用程序的任何部分创建为一个可组合和可重用的 "组件"。你和你的团队可以共享一个组件工具箱,以便更快、更一致地共同构建更多的应用程序。

  • 创建和组成 "应用构件"。UI元素、完整功能、页面、应用程序、无服务器或微服务。使用任何JS堆栈。
  • 在团队中轻松分享和重复使用组件。
  • 跨项目快速更新 组件
  • 让困难的事情变得简单。单体设计系统微前端

试用Bit开源和免费→。

了解更多


在JavaScript中实现大文件的并发下载》最初发表在《Bits and Pieceson Medium》上,人们通过强调和回应这个故事来继续对话。

猜你喜欢

转载自juejin.im/post/7129290982981369864