原因
- 提高上传稳定性,当网络出现波动这个上传可能失败,通过断点续传,我们不需要重新上传整个文件
- 不管是客户端和服务端的内存消耗都会减少
- 通过小块上传,可以充分利用带宽,提升上传速度
- 可以提供更精确的上传进度反馈
首先对文件进行切片,传入一个file对象,file对象继承了blob(/blab/)的slice(/slais/)方法,使用它对文件按指定大小进行切割获得blob切片数组。
js
const createFileChunk = (file: UploadRawFile, size = CHUNKSIZE) => {
const fileChunkList = []
let cur = 0
while (cur < file.size) {
fileChunkList.push({
file: file.slice(cur, cur + size)
})
cur += size
}
return fileChunkList
}
针对文件生成唯一标识,使用spark-md5(/spa:rk/)生成hash。考虑到这一步将占用大量资源,阻塞主线程。因此在web worker中进行这个操作
调用初始化上传接口,请求参数是切片数,文件hash。返回taskId
调用切片上传接口,入参切片序号,taskId,请求体里文件切片(formData),返回成功,更新上传进度
但是浏览器限制并发请求的个数,如果使用promise.all一次性的并发请求太多可能导致请求直接失败,使用p-limit帮助我们解决限制并发个数的问题
优化:
秒传,在初始化上传接口中如果后端根据hash发现文件已经存在,则会返回一个特殊的状态码表示该文件已存在
断点上传,调用初始化上传接口,如果没有上传完,返回缺失的切片序号,前端再补充上传缺失的切片即可
暂停上传,axios提供的AbortController取消上传
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
恢复上传,已知已上传成功列表,只需要上传除此之外的切片
webworker传递大数据
主线程与webwork传递的数据是复制的,而不是共享,需要经过序列号与反序列化,大部分浏览器使用结构化克隆算法(structured clone algorithm)来实现。
但是可转移对象( Transferable object)通过零拷贝操作从一个上下文转移到另一个上下文,这在发送大型数据集时可带来巨大的性能提升。
这些资源可以从一个上下文转移到另一个,但是资源一次只能在一个上下文可用