web worker计算md5实践及遇到的坑
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web worker计算md5实践及遇到的坑相关的知识,希望对你有一定的参考价值。
web worker计算md5实践及遇到的坑
最近项目要实现大文件的分块上传及断点续传,其中文件的md5是判断文件或文件块是否已被上传的重要依据。
1. 阶段一
编码初期,直接在公共方法中写了一个传入file
返回md5
的函数,供文件上传模块使用。关键代码如下:
/**
* 获取文件的md5
* @param {*} file 文件对象
*/
import SparkMD5 from ‘spark-md5‘
export async function getFileMd5(file) {
return new Promise((resolve) => {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
const chunkSize = 1024 * 1024 * 5
const chunks = Math.ceil(file.size / chunkSize)
let currentChunk = 0
const spark = new SparkMD5.ArrayBuffer()
const fileReader = new FileReader()
fileReader.onload = function(e) {
spark.append(e.target.result)
currentChunk++
if (currentChunk < chunks) {
loadNext()
} else {
resolve(spark.end())
}
}
fileReader.onerror = function(error) {
console.error(error)
resolve()
}
function loadNext() {
const start = currentChunk * chunkSize
const end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
}
loadNext()
})
}
2. 阶段二
考虑到计算md5
涉及大量的计算,因此可以利用Web Worker
技术,将计算的任务交给其它线程使用,避免主线程的阻塞导致的页面卡顿。改造步骤如下:
- 新建
md5.worker.js
文件,将计算md5
得逻辑移动到该文件中。
import SparkMD5 from ‘spark-md5‘
addEventListener(‘message‘, function(event) {
getFileMd5(event.data)
}, false)
function getFileMd5(file) {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
const chunkSize = 1024 * 1024 * 5
const chunks = Math.ceil(file.size / chunkSize)
let currentChunk = 0
const spark = new SparkMD5.ArrayBuffer()
const fileReader = new FileReader()
fileReader.onload = function(e) {
spark.append(e.target.result)
currentChunk++
if (currentChunk < chunks) {
loadNext()
} else {
postMessage(spark.end())
}
}
fileReader.onerror = function(error) {
console.error(error)
postMessage()
}
function loadNext() {
const start = currentChunk * chunkSize
const end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
}
loadNext()
}
- 改造之前为分块上传模块提供的函数
/**
* 获取文件的md5
* @param {*} file 文件对象
*/
import Md5Worker from ‘worker-loader!../workers/md5.worker‘
export async function getFileMd5(file) {
return new Promise((resolve) => {
const md5Worker = new Md5Worker()
md5Worker.onerror = () => {
md5Worker.terminate()
resolve()
}
md5Worker.onmessage = (event) => {
md5Worker.terminate()
resolve(event.data)
}
md5Worker.postMessage(file)
})
}
- 安装worker-loader,
npm i -D worker-loader
- 安装完成后运行打包命令(例如
npm run build
),可以看到在dist
目录下输出了对应的[hash].worker.js
文件。
3. 遇到的坑
最开始是参考官网在vue.config.js
中配置loader
,配置如下
{
module: {
rules: [
{
test: /.worker.js$/,
use: { loader: ‘worker-loader‘ }
}
]
}
}
运行打包命令,提示Cannot read property ‘createChildCompiler‘ of undefined
,定位到需要设置parallel: false
,该配置是是否启用多核打包(当时寻思代价不小啊)。
设置该配置之后,可以正常打包了,dist
目录下出现了.worker.js
文件。然而当我以为大功告成的时候,再次运行打包命令(配置文件没有任何变化),神奇的事情出现了,dist
目录下没有.worker.js
文件了!!!但只要我修改vue.config.js
文件,哪怕在任何地方输出log,运行打包命令.worker.js
文件又会出现。因此最终使用了以上的解决方案。
同时,在此期间,还调研了worker-plugin,然而在打包的时候,总是会对md5.worker.js
报ESLint
相关的错误,即便我关闭了对该文件的代码检测。唯一的区别是,关闭代码检测之后,错误变少了。
以上是关于web worker计算md5实践及遇到的坑的主要内容,如果未能解决你的问题,请参考以下文章