JavaScript 大文件上传
N久以前
N久前遇到的问题,当时简单的解决了一下,现在在写一个StorageBucket,需要有一个Demo,所以又回过头来研究。
来看看之前是这么解决的:
let slice_size = 1024 * 1024; // 1MB 分块大小
let totalSliceNum = 0; //总分块数量
let now = 0; //当前分块
let file = document.getElementById("file").files[0];
totalSliceNum = Math.ceil(file.size / slice_size);
print("size|" + file.size);
print("name|" + file.name);
print("type|" + file.type);
print("slice|" + totalSliceNum);
while(now < totalSliceNum) {
let s = now * slice_size;
let e = (now + 1) * slice_size;
if(e > file.size) {
e = file.size;
}
let chunk = file.slice(s,e); //切取一块
//jquery.ajax 发送文件块数据
now += 1;
}
看起来没错,网上也大部分都是这么写的,按顺序一块一块上传,但实际上使用你会发现,浏览器卡爆了,页面完全不渲染,幸好是给同学用的,让他F12在控制台看进度。
我们浏览器中的js是单线程的,我们分片时会卡死在file.slice
这里,因为它要从文件中读出一块,它卡死在这占据了整个线程,导致整个页面无法渲染。不过我们可以用FileReader
来异步读取,而不是等他读取,卡到无法渲染,所以有了下面的版本:
let slice_size = 1024 * 1024; // 1MB 分块大小
let totalSliceNum = 0; //总分块数量
let now = 0; //当前分块
let file = document.getElementById("file").files[0];
totalSliceNum = Math.ceil(file.size / slice_size);
print("size|" + file.size);
print("name|" + file.name);
print("type|" + file.type);
print("slice|" + totalSliceNum);
while(now < totalSliceNum) {
let s = now * slice_size;
let e = (now + 1) * slice_size;
if(e > file.size) {
e = file.size;
}
let chunk = file.slice(s,e); //切取一块
let reader = new FileReader();
reader.readAsArrayBuffer(chunk);
reader.onload = function() {
//当块加载好了,会执行这个函数
//console.log(new Blob([reader.result]));
//jquery.ajax 发送文件块数据
//这里要传递当前分块与总块数量,方便后端合成,因为块不再是顺序上传
}
now += 1;
}
效果
最后
博客很少更了,我现在不像以前一样那么有动力,不过...