2021年7月

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;
}

效果

21072601.png

最后

博客很少更了,我现在不像以前一样那么有动力,不过...