大文件上传(断点续传等)

文件切片

/**
 * 文件切片
 * @param {File} file 切片文件
 * @param {number} pieceSize 切片大小
 * @param {string} fileKey 文件唯一标识
  */
 const getSliceFile = async (file: File, pieceSizes = 50, fileKey: string) => {
   const piece = 1024 * 1024 * pieceSizes;
   // 文件总大小
   const totalSize = file.size;
   const fileName = file.name;
   // 每次上传的开始字节
   let start = 0;
   let index = 1;
   // 每次上传的结尾字节
   let end = start + piece;
   const chunks = [];
   while (start < totalSize) {
     const current = Math.min(end, totalSize);
     // 根据长度截取每次需要上传的数据
     // File对象继承自Blob对象,因此包含slice方法
     const blob = file.slice(start, current);
     
     const hash = (await getHash(blob)) as string; // 除了hash之外还可以用uuid来标识
     
     chunks.push({
       file: blob,
       size: totalSize,
       index,
       fileSizeInByte: totalSize,
       name: fileName,
       fileName,
       hash,
       sliceSizeInByte: blob.size,
       fileKey,
    });
     start = current;
     end = start + piece;
     index += 1;
  }
   return chunks;
};

上传 chunks

  • 通过Promise.all | Promise.allSettled | 遍历进行上传,出错后进行断点续传
try{
  await Promise.all([...])
}catch(e){
	// ...
}

所有分片上传成功后,发送合并 chunks 请求

  • 可以每次上传成功后 id+1,当 id 和 chunks 分片数量相等时,发送合并请求

断点续传

  • 通过后端返回已上传成功的chunk的序列号集合或者每次上传成功将序列号存在localStorage里
  • 通过上一步获取未上传成功的chunk ,继续上传
const getTasks = (
   files: FileInfo[],
   uploadId: string,
   fileKey: string,
   finish: number[], // 后端返回已成功上传的序列号
): Promise<CommonResponse_LargeFileUploadResponse_>[] => {
   const tasks: Promise<CommonResponse_LargeFileUploadResponse_>[] = [];
   const currentTaskIndex: number[] = [];
   files.forEach((chunk: FileInfo) => {
     if (finish.includes(chunk.index)) {
       return;
    }
     // 未上传成功的chunk
     currentTaskIndex.push(chunk.index);
     const formData = new FormData();
     formData.append('file', chunk.file);
     // @ts-ignore
     formData.append('sliceIndex', chunk.index);
     formData.append('hash', chunk.hash);
     formData.append('uploadId', uploadId);
     // @ts-ignore
     formData.append('fileSizeInByte', chunk.sliceSizeInByte);
     tasks.push(sliceUpload(formData));
  });
   return tasks;
};

刷新网页继续上传

  • 和断点续传同理,将已成功上传的 chunks 序列号保存到 localStorage 中或通过请求后台获取
  • 根据上一步找到未上传的chunks,继续上传

优化

闲时上传

  • 通过 requestIdleCallback 在浏览器空闲时计算或发请求

webWorker

  • 通过 webWorker 来进行文件的分片计算

限制请求数量

  • 因为浏览器有6-10个连接数的限制,所以需要控制分片的请求数量,最好一次不超过三个
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值