大文件切片上传
569字约2分钟
2024-07-25
为什么会有切片上传呢?
其实主要是在一些业务场景中,文件过大,单次请求时间过长。用户体验感差、切无法控制才会有切片上传的场景需求出现。
工具
我们需要使用到spark-md5
,因为我们要对文件进行切片,然后对切片进行计算hash值,最后将hash值和切片一起上传。
其主要目的是保证文件的唯一性。
npm install spark-md5
代码实现
此处只写了文件切片的流程、且性能一般,因为在计算文件hash值的时候是CPU密集型任务,由于JS是单线程的所以造成大量的时间浪费。
import SparkMD5 from 'spark-md5'
interface FileInfo {
/** blob文件流数据 */
blob: Blob
/** 文件hash值 */
hash: string
/** 文件切片索引 */
index: number
/** 文件名 */
fileName: string
}
export default class FileModule{
/** 当前设备线程,此处优化性能使用,暂且忽略 */
static threadCount: number = navigator.hardwareConcurrency || 4
/**
* @param file File文件体
* @param size 切片单位Mb
* @returns 返回切片文件信息
*/
static async sliceFile(file: File, size: number = * 5):Promise<FileInfo[]> {
/** 切片大小 */
const chunkSize = size * 1024 * 1024;
/** 切片次数 */
const chunkCount = Math.ceil(file.size / chunkSize)
/** 切片列表 */
const chunks:FileInfo[] = []
for (let i = 0; i < chunkCount; i++) {
const start = i * chunkSize;
const end = Math.min(file.size, start + chunkSize);
const blob = file.slice(start, end);
const hash = await this.hashFile(blob);
const chunkInfo = {
blob,
hash,
index: i,
fileName: file.name
}
chuns.push(chunkInfo)
}
return chunks
}
static async hashFile(blob:Blob):Promise<string>{
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = (e) => {
const spark = new SparkMD5.ArrayBuffer();
spark.append(e.target?.result as ArrayBuffer);
const hash = spark.end();
resolve(hash)
}
fileReader.onerror = (e) => {
reject(e)
}
fileReader.readAsArrayBuffer(blob)
})
}
}
总结
如果需要性能优化,可以使用Web Worker
,将计算hash值放到另一个线程中,这样就不会阻塞主线程了。
思路:
- 通过api获取设备多少个线程,便开启多少个线程。
- 根据线程数规划每个线程将要切片的数量,可能有的线程数量多有的少,规划的时候注意条件判断。
- 将子线程返回的数据list拍扁,装在一起返回结果。
- 总数据处理建议
arr[i] = list
,避免有的线程返回数据慢,导致数据错乱。