Java分块上传文件_使用异步管理队列处理大文件分块上传

关于大文件分块上传,这里推荐一篇文章。没想到是字节跳动的前端面试题。

这篇文章对大文件分块上传整体的实现思路描述得比较全面,然而在实际的业务开发中还会遇到一些细节问题。

比如:文件分块后,直接用 Promise.all 发起所有上传请求是否会有性能问题?

由于 HTTP1.x 不支持多路复用,所以浏览器每发起一个 HTTP请求就会打开一个 TCP 会话。对于大多数浏览器,每个主机(域名)最多同时支持6个 TCP 连接。也就意味着客户端每次最多只能并发6个请求。当请求数超过限制后,后续的请求必须得排队等候。有些面试也会问怎么优化请求资源加载,常见的做法就是增加新的域名分区。

目前,市面上大部分还是以 HTTP1.x 为主,使用 Promise.all 并发所有请求,是会阻塞后续的请求,假设此时用户在网页有其他的请求交互,那么界面就会有一直处于 loading 状态直到原先的排队请求都得到响应。 (提示正在等待可用的套接字...)

我们既想同时上传多个小块文件,又不能越过并行6个请求的限制,就需要进行队列管理。

假设,我们每次并发 4 个上传文件的请求,这样能确保还剩 2 个连接数以支持用户在页面进行其他的交互。

这4个请求里,任意一个请求得到响应之后,马上发起下一个请求,以充分利用请求的资源。

我们再完善下业务场景,此时若一文件体积为 50M,我们以 5M 为一块,那么则需要上传 10 个文件块。

ATM(异步任务管理队列)

我们来通过引入一个 ATM 来帮助我们管理这些事情。 项目地址

yarn add x-atm

复制代码import ATM from 'x-atm'

// 设定最大并行数为 4

const atm = new ATM({maxParallel: 4})

// 假设来源是拖拽上传

const file = event.originalEvent.dataTransfer.files[0]

// 设定上传路径

const uploadUrl = 'https://xxxx'

// 上传特定的文件块

function singleTask(start, end) {

return function() {

const xhr = new XMLHttpRequest();

xhr.open('POST', uploadUrl);

xhr.send(file.slice(start, end));

return new Promise((resolve, reject) => {

xhr.onreadystatechange = function() {

if (xhr.readyState !== 4) {

return;

}

if (xhr.status >= 200 && xhr.status < 400) {

resolve(xhr.statusText);

} else if (xhr.status >= 400) {

reject(xhr.status);

} else if (xhr.status === 0) {

reject(xhr.status);

}

};

});

}

}

const FIVE_M = 5242880; // 5M

for(let i = 0; i < 10; i++) {

let tempStart = start;

let tempEnd = end;

// 上传 [0, 5M], [5M, 10M], ... [45M, 50M]

const asyncTask = singleTask(FIVE_M * i, FIVE_M * (i + 1))

atm.push(asyncTask)

}

atm.start() // 执行异步任务

复制代码

这样,我们就能满足我们管理任务队列的基本需求。

为便于大家理解,这里提供一个 demo。

失败重传

假设,其中的某个文件块由于某些原因,上传失败了。我们需要重新上传该文件块。

那么,我们可以启动严格模式,以确保异步任务完成

const atm = new ATM({maxParallel: 4, strict: true, maxRetry: 3})

复制代码

strict 表示,我们必须要让每个异步的任务被 resolve 才算这个任务执行成功; maxRetry 表示,假设这个异步任务执行失败了,它可以尝试再次执行的次数。

查询进度

我们想在每个任务完成后,查询大文件上传进度的话。我们可以在这个任务后面添加 resolve 回调。

const asyncTask = singleTask(FIVE_M * i, FIVE_M * (i + 1))

asyncTask.resolve = () => {

const finished = atm.query().finished; // 已经执行了多少个分块上传的任务

const failed = atm.query().failed; // 当前有多少个分块上传失败了

const count = atm.query().count; // 一定有多少个分块

// 我们可以通过 finished - failed 得到已经成功上传的分块

}

复制代码

其他功能

除此之外,ATM 还提供暂停异步任务和恢复执行的操作。(假设我们想暂停上传某个大文件的话)

atm.stop()

atm.continue()

复制代码

结语

ATM 可以帮助我们并发特定数量的异步任务,还提供处理异步执行失败的重试操作的机制,这是整个功能的核心。

如果你的网站能预期后续用户会访问很多资源,那么你可以用 ATM 在后台悄悄加载某些资源,待用户下次再请求时,就可以从缓存中读取数据。

参考资料

《Web性能权威指南》

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[使用异步管理队列处理大文件分块上传]http://www.zyiz.net/tech/detail-118220.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值