1.安装worker-loader
npm install worker-loader
2.配置worker-loader
// vue.config.js配置
chainWebpack: (config) => {
config.module
.rule('worker')
.test(/\.worker\.js$/) // 匹配文件名为xxx.worker.js的文件
.use('worker-loader')
.loader('worker-loader')
.end()
},
3.创建md5.worker.js文件
import SparkMD5 from "spark-md5";
// 生成md5
function createFileMd5 (file) {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
if(!blobSlice) {
// 浏览器不兼容处理
return ''
}
let chunkSize = 1 * 1024 * 1024, // 分割文件大小为1MB
chunks = Math.ceil(file.size / chunkSize),
currentChunk = 0,
spark = new SparkMD5.ArrayBuffer(),
fileReader = new FileReader()
return new Promise((resolve)=> {
const now = new Date()
fileReader.onload = function (e) {
spark.append(e.target.result)
currentChunk++
if (currentChunk < chunks) {
loadNext()
} else {
const r = {
md5: spark.end(),
time: `${(new Date().getTime() - now) / 1000}s`,
}
resolve(r)
}
}
fileReader.onerror = function () {
resolve(null)
}
function loadNext () {
let start = currentChunk * chunkSize,
end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)) // 这里的file要是file.raw,否则会报错
}
loadNext()
})
}
onmessage = async function (e) {
const data = e.data
const result = await createFileMd5(data.file) // 要看postMesage传过来的数据,如果是file.raw,则直接去data
postMessage(result) // 返回结果
}
4.主要实现逻辑
import Md5Worker from './md5.worker.js'
export default {
name: "uploader",
data () {
return {
chunkSize: 5 * 1024 * 1024,
worker: null,
}
},
destroyed () {
this.worker = null
},
}
async onChange (params) {
this.worker = new Md5Worker()
const file = params.raw
// 调用计算md5值的方法,获取md5以及时间
const { md5, time } = await this.calculateMd5Worker(file)
console.log(md5, '<-----md5------>用时:', time)
// filePath为文件路径,shardFiles为切片文件的数据,是个数组
const { filePath, shardFiles } = await this.checkFile(md5)
// 判断filePath存在,则文件无需上传,直接成功,实现文件秒传功能。
if (filePath) {
// 通知父级页面上传进度,此处和忽略。
this.$emit('upload', { progress: 100, tip: '上传进度' })
return false
} else {
// 将shardFiles返回的数据存放在list中,调用创建切片接口,进入切片上传逻辑。
let list = shardFiles || []
this.startCreateChunk(file, md5, list)
}
},
async calculateMd5Worker (file) {
return new Promise((resolve) => {
this.worker.postMessage({ file })
this.worker.onmessage = e => {
const md5 = e.data
if (md5) resolve(md5)
}
})
},
参考文档:
https://zhuanlan.zhihu.com/p/668425206