场景和定义
文件分片上传就是把文件分成一个个小块然后逐个上传,以文件的[md5]作为文件的唯一标识,这样即使上传过程中因某些原因中断了,等到下次再上传的时候,通过对比文件的md5来确认是否是相同文件,就可以在上次的基础上继续上传。
用到的知识点
files文件分片、计算MD5值(sparkMD5)、WebWorker
files文件分片
使用 file.slice将文件切片,然后使用 FileReader 读取 blob,API 为 readAsArrayBuffer,最后在FileReader.onload(e)读取完成的方法中,完成相应的逻辑
var blob = file.slice( start, end ) //start:开始位置,end:结束位置
var fileReader = new FileReader();
fileReader.readAsArrayBuffer( blob );
fileReader.onload = (e) => {
...
}
计算文件 MD5 值(sparkMD5)
使用spark-md5.js插件能快速计算文件的md5。
WebWorker
我们都知道道JavaScript是单线程的,阮一峰的文章里面说:JavaScript的主要用途是与用户互动和操作DOM,这决定了它只能是单线程。否则会带来很复杂的同步问题。比如说:假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
那也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。
基本用法
1.主线程里面调用Worker()构造函数,变可创建worker线程
var worker = new Worker('work.js'); //此处的work.js必须来源于网络
2.然后就可以调用worker.postMessage()向worker线程发送数据
worker.postMessage(param)
3.接着通过worker.onmessage监听函数,接收子线程发回来的数据
worker.onmessage = function (e) {
//e.data 就是接收到的数据
...
}
4.子线程里面通过self.onmessage 来接收主线程发来的数据
self.onmessage = (e) => {
//e.data 就是接收到的数据
...
}
5.子线程里面通过self.postMessage像主线程发送数据
self.postMessage(param)
6.完成后,关闭线程
因为Worker 线程创建成功,就会始终运行,不会被主线程上打断。这就比较耗费资源,所以一旦使用完毕,就应该关闭子线程。
worker.terminate();//主线程关闭
self.close() //子线程关闭
7.加载其他脚本importScripts
//该方法可以加载多个脚本文件
importScripts('script1.js', 'script2.js');
总体思路:
切片上传
1.通过input [ file ] 选择好文件
2.拿到文件开始计算切片
3.分片读取文件,计算文件hash值
4.根据hash值,后台查看该文件是否上传过,如果上传过,直接提示上传完成,即秒传。如果上传过一部分,则后台返回已经上传的文件切片。
5.在切片的数组中过滤掉已经上传的文件,组装一个request请求池。
6.通过Promise.all方法,等到request请求池完成所有上传后,通知后台合并文件切片。
worker参考文章:https://www.ruanyifeng.com/blog/2018/07/web-worker.html