背景
其实对于前端,很多需要上传比如几百兆 文件解析的业务场景下,可能会出现哪些问题呢
首先我们可以做的是确定方案
- 首先针对于分治思想,可以把大文件拆解为一个个独立的小文件
- 为了能够在服务端进行重组,肯定是需要类似于索引序号,类似http2.0的流id机制。
具体流程
- 为首先把文件用md5 算法进行加密,进行校验-- md5 本身作为一种消息摘要算法,用来判断文件的内容是否已经被重复上传,这样能够校验文件内容。
- 为了能够避免一次性上传过大的文件,那就进行分片--分多少片合适呢
- 那服务端接受到之后,为了能够进行文件重组,还需要向其传递对应分块的索引号。
- 同时在上传分片的过程中,优先传送对应md5 服务端先来校验一下,当前的分块,有没有被上传过,这样就能加速文件上传,跳过当前分块。
- 那怎么提升文件上传的速度,其实可以通过并发上传,分块,不过不能无限并非,因此还需要进行限制,一定时间内,只能并非一部分.
代码实例
function uploadFile(file) {
const CHUNK_SIZE = 1 * 1024 * 1024; // 分片大小,这里以1MB为例
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
uploadChunk(chunk, i);
}
}
function uploadChunk(chunk, chunkIndex) {
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('index', chunkIndex);
fetch('/upload', { method: 'POST', body: formData })
.then(response => response.json())
.then(data => console.log('Chunk uploaded', data))
.catch(error => console.error('Error in uploading chunk', error));
}
// 调用示例
const file = document.querySelector('input[type="file"]').files[0];
uploadFile(file);
并发限制
- 如果当前文件分片过多,那么必然会导致并非数量过多导致卡顿,因此需要限制并发数,以下一个小案例
- 基本思路就是预先先进行限制数并非,之后,每一个promise状态成功,就继续请求。
const promiseAllLimit = (promises, limit) => {
let currentIndex = 0;
const run = () => {
return new Promise((resolve, reject) => {
const runPromise = promises[currentIndex];
resolve(runPromise())
currentIndex++
}).then(() => {
if (currentIndex < promises.length) {
run()
}
})
}
// 依次执行
for (let i = 0; i < limit; i++) {
run()
}
}
// 测试
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
const tasks = [() => new Promise((resolve) => setTimeout(() => { console.log('1111'); resolve(1) }, 1000)), () => new Promise((resolve) => setTimeout(() => { console.log('2222'); resolve(2) }, 1000)), () => new Promise((resolve) => setTimeout(() => { console.log('3333'); resolve(1) }, 1000)), () => new Promise((resolve) => setTimeout(() => { console.log('4444'); resolve(4) }, 1000))];
promiseAllLimit(tasks, 2)