【前端】大文件切片上传性能优化 使用 web worker 多线程
2026/6/6 16:11:31 网站建设 项目流程

线程代码

worker.js

//实例化一个 XMLHttpRequest 对象 let xhr = new XMLHttpRequest(); let 延迟关闭线程等待时间毫秒 = 6000 function 取消上传(){ try { xhr.abort() }catch (e) { } } addEventListener('message', e => { const { type, data } = e.data // console.log('子线程:',data) switch (type){ case '上传文件': 上传文件(data.file,data.第几个, data.子线程id) break case '取消上传': 取消上传() break case '安全关闭线程': 取消上传() setTimeout(self.close, 延迟关闭线程等待时间毫秒) break case '关闭线程': self.close() break default: console.log('未知命令') break } // postMessage('子线程发送的消息') }) function 上传文件 (file, 第几个, 子线程id){ console.log('子线程id:' + 子线程id + ', 第:' + 第几个 + '片-开始上传') // 这个要放到调用open函数之前!!! xhr.upload.onprogress = function (e) { // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度 if (e.lengthComputable) { // 多个文件总共大小,以及已上传大小 // console.log(e.total,e.loaded); // e.loaded 已传输的字节 e.total 文件传输需要的总字节 var percentComplete = Math.ceil((e.loaded / e.total) * 100); // Math.ceil() 向上取整 // console.log('子线程id:' + 子线程id + ', 第几片:' + 第几个 + '-当前进度:', percentComplete) } }; // 文件上传成功 xhr.upload.onload = function () { // console.log('文件上传完成') }; // open 必须放 xhr.send() 前面 //设置请求方式及接口地址 xhr.open('POST', 'http://127.0.0.1:8088/robot/flow/upload', true); // xhr.setRequestHeader('Content-Type', 'application/octet-stream'); xhr.onload = function () { // self.postMessage({ status: 'chunk_uploaded', message: 'Chunk uploaded successfully' }); }; xhr.onerror = function () { console.log('上传出错-子线程id:' + 子线程id + ', 第:' + 第几个 + '片') // self.postMessage({ status: 'error', message: 'Error uploading chunk' }); }; const formData = new FormData(); formData.append('file', file); // formData.append('currentChunk', currentChunk + 1); // formData.append('totalChunks', totalChunks); xhr.onreadystatechange = (e) => { //服务端响应后 /* 0 未打开,xhr.open()方法还未被调用. 1 未发送, xhr.send()方法还未被调用. 2 已获取响应头,xhr.send()方法已经被调用, 响应头和响应状态已经返回. 3 正在下载响应体, xhr.响应体下载中; responseText中已经获取了部分数据. 4 请求完成, 整个请求过程已经完毕. * */ if (xhr.readyState == 4) { //判断客户端是否可以使用 if(xhr.status == 200){ //表示成功处理请求 // 如果定义为 xhr.responseType='json';,控制台包提示格式错误,建议不设置,使用默认设置 console.log('子线程id:' + 子线程id + ',第几片:' + 第几个 + '-上传完成:', xhr.responseText) self.postMessage({ type:'上传完成', success: true, message: '上传成功' }); }else{ console.log(xhr.status+' '+xhr.statusText) } } } // 一般放在最后 xhr.send(formData) } export default {}

引用线程 指定线程数

import Worker from "worker-loader!@/workers/worker"; //线程集合 var workers = [] const 线程数 = 5

代码 vue js 都可用

<template> <div> <input type="file" id="fileInput" /> <a-button @click="点击上传按钮" type="primary">上传</a-button> <a-button @click="取消上传" type="primary">取消上传</a-button> <!-- 进度条--> <progress id="progressBar" max="100" value="0"></progress> <div id="status"></div> </div> </template> <script> import Worker from "worker-loader!@/workers/worker"; //线程集合 var workers = [] const 线程数 = 5 //文件 var file; export default { components: { }, data() { let that = this return { 当前第几片 : 0, 总片数 : 0, 每片大小: 1024 * 1024 * 99, // 99 MB chunks (adjust as needed) } }, setup(){ // console.log(this.$route.currentRoute.value.query) // const StrUtil = this.$WTool.StrUtil }, created() { let that = this }, mounted() { }, methods: { 初始化线程(){ let that = this //关闭之前的线程 for (let i = 0; i < workers.length; i++) { workers[i].postMessage({type:'安全关闭线程'}) } //清空线程 workers = [] //初始化线程 for (let i = 0; i < 线程数; i++) { workers.push(new Worker()) console.log('初始化线程:' + (i+1)) } //初始化线程监听回调 for (let i = 0; i < workers.length; i++) { let worker = workers[i] worker.onmessage = e => { const { type, success } = e.data switch (type){ case '上传完成': // console.log('主线程:上传完成,继续调用上传方法') that.开始上传文件(i) break default: console.log('未知命令', type) break } } console.log('初始化线程onmessage:' + (i+1)) } }, 取消上传(){ console.log('取消上传开始') for (let i = 0; i < workers.length; i++) { workers[i].postMessage({type:'安全关闭线程'}) } console.log('取消上传结束') }, 点击上传按钮(){ //获取文件 file = document.getElementById('fileInput').files[0] //切片 this.总片数 = Math.ceil(file.size / this.每片大小); console.log('分片数量:' + this.总片数) this.初始化线程() //开始上传 for (let i = 0; i < workers.length; i++) { this.开始上传文件(i); } }, 开始上传文件(子线程id){ let that = this //获取线程 let worker = workers[子线程id] if(that.当前第几片 >= that.总片数){ console.log('第几个线程:' + 子线程id + ', 上传结束') return } const start = that.当前第几片 * this.每片大小; const end = Math.min(file.size, start + this.每片大小); //文件切片 const chunk = file.slice(start, end); if(chunk){ // console.log("子线程id:" + 第几个线程 + '-线程,让子线程上传文件,当前第几片:', that.当前第几片) worker.postMessage({type:'上传文件', data:{file:chunk, 第几个:that.当前第几片, 子线程id:子线程id}}) that.当前第几片++ } } } } </script> <style> </style>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询