在做一些大文件的批量上传时,需要计算文件的md5值,1G以上的文件计算时长可长达几秒,严重时会影响主线程的UI交互,因此使用webworker创建多线程计算md5,在主线程创建worker,在worker中计算md5,计算完成后关闭worker,并将结果返回给主线程。
webworker是什么
一个worker就是使用一个js脚本文件通过构造函数创建的一个对象,这个文件包含将在工作线程中运行的代码,这个对象供主线程操作 Worker。Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
怎么用
1、创建js脚本文件 file.worker.js
// file.worker.js
onmessage = function (e) {
// 处理数据
console.log(e.date)
if(e.date==='foo'){
// 将结果返回主线程
postMessage('bar')
// 关闭worker
close()
}
}
复制代码
2、创建worker实例
// 主线程文件
import Worker from './file.worker'
const myWorker = new Worker()
// 主线程向worker发消息
myWorker.postMessage('foo')
// worker处理的结果返回给主线程
myWorker.onmessage = (e) => {
console.log(e.data)
// 关闭worker
myWorker.terminate()
}
myWorker.onerror = (err) => {
// 错误处理
}
复制代码
可以看出:
- 1 无论是主线程还是worker线程均用postMessage发送消息,onmessage接受消息
- 2 事件对象的data属性可以获取相互传送各种类型的数据
- 3 为了节省系统资源,必须关闭 worker。主线程使用terminate();worker中使用close();
需要注意的一点是: 传递的数据是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。>
这里插入一个遇到的浏览器bug:
在file.worker.js 中使用到File接口,在safari浏览器的一些稍低版本中,会报错:File is undefined,解决办法是使用Object.getPrototypeOf()
返回file的原型。
const proto = File.prototype // 报错
const proto = Object.getPrototypeOf(file) // 正常
复制代码
参考: