通过传统的分片上传,发现时间还说有点过长,因为这是一个cpu密集任务,主线程异常忙碌,会导致页面卡顿,所以这里的大文件上传使用了多线程的方式,这样在保证效率的同时页面也不会卡顿。
import { createChunk } from "./worker";
const inputFile = document.querySelector(
'input[type="file"]'
) as HTMLInputElement;
inputFile.onchange = async (e: any) => {
const file = e.target.files[0];
console.time("cutFile");
//const chunks = await oldCutFile(file);
const chunks = await newCutFile(file);
console.timeEnd("cutFile");
console.log(chunks, "chunks");
};
const CHUNK_SIZE = 1024 * 1024;
// 这种耗时太久
async function oldCutFile(file: any) {
const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
const result = [];
for (let i = 0; i < chunkCount; i++) {
const chunk = await createChunk(file, i, CHUNK_SIZE);
result.push(chunk);
}
return result;
}
const THREAD_COUNT = navigator.hardwareConcurrency || 4;
async function newCutFile(file: any) {
return new Promise((resolve, reject) => {
const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
const threadChunkCount = Math.ceil(chunkCount / THREAD_COUNT);
const result = [];
let finishCount = 0;
for (let i = 0; i < chunkCount; i++) {
const worker = new Worker("/src/worker.ts", {
type: "module",
});
let end = (i + 1) * threadChunkCount;
if (end > chunkCount) {
end = chunkCount;
}
const start = i * threadChunkCount;
worker.postMessage({
file,
CHUNK_SIZE,
startChunkIndex: start,
endChunkINdex: end,
});
worker.onmessage = (e: any) => {
for (let i = start; i < end; i++) {
result[i] = e.data[i - start];
}
worker.terminate();
finishCount++;
if (finishCount === THREAD_COUNT) {
resolve(result);
}
};
}
});
}
import SparkMD5 from "spark-md5";
/**
*
* @param file 文件
* @param index 切片下标
* @param size 切片大小
* @returns
*/
export function createChunk(file, index, size) {
return new Promise((resolve) => {
const start = index + size;
const end = start + size;
const spark = new SparkMD5.ArrayBuffer();
const fikeReader = new FileReader();
const blob = file.slice(start, end);
fikeReader.onload = (e: any) => {
spark.append(e.target.result);
resolve({
start,
end,
index,
hash: spark.end(),
blob,
});
};
fikeReader.readAsArrayBuffer(blob);
});
}
onmessage = async (e: any) => {
const {
file,
CHUNK_SIZE,
startChunkIndex: start,
endChunkINdex: end,
} = e.data;
const proms = [];
// const a = await createChunk(file, 1, CHUNK_SIZE);
// console.log(a, "aaaaaaaaaa");
for (let i = start; i < end; i++) {
proms.push(createChunk(file, i, CHUNK_SIZE));
}
const chunks = await Promise.all(proms);
postMessage(chunks);
};