1.template
<a-upload :file-list="objData.fileList" name="file" :beforeUpload="beforeUpload" class="zlcUpload">
<a-button>
<a-icon type="cloud-upload" />
</a-button>
</a-upload>
<a-button size="large" type="primary" :disabled="!objData.fileList.length" @click="upload" class="zlcBtn">
上传
</a-button>
2.script
data() {
return {
objData: {
chunkSize: 1 * 1024 * 1024,
fileList: [],
sliceList: [],
md5: null,
fileName: null,
finishSliceList: [],
uploadStart: 0
},
visible: false,
uploadCompleted: false,
}
},
methods: {
beforeUpload(file) {
this.objData.fileList = [file];
return false;
},
}
3.点击上传,进行切片,以及获取文件名,md5唯一标识
async upload() {
this.visible = true;
let file = this.objData.fileList[0];
this.objData.fileName = file.name;
let fileMd5 = await this.getFileMd5(file);
if (file.size < this.objData.chunkSize) {
} else {
this.objData.sliceList = this.getSliceList(file);
this.hadUpload().then(res => {
if (res.message == '上传成功') {
this.objData.uploadStart = this.objData.sliceList.length
this.uploadCompleted = true
return
}
let finishArr = res.result;
this.objData.uploadStart = !finishArr ? this.objData.sliceList.length : finishArr.length;
if (!finishArr.length ||( finishArr.length < this.objData.sliceList.length)) {
//并发请求
this.concurRequest(this.objData.sliceList, 3).then(res => {
let { md5, fileName } = this.objData;
console.log('并发请求结果', res)
let rejectResp = res.some(item => item.code != 200) //是否有失败的
if(!rejectResp){ //全部成功
mergeFile({ md5, fileName }).then(res => {
this.uploadCompleted = true
})
}else{
//至少一个失败
}
})
}else{
}
// //开始上传
// let uploadList = this.objData.sliceList.map(item => {
// if (finishArr.includes(item.flag.toString())) {
// } else {
// return new Promise((resolve, reject) => {
// const formData = new FormData();
// formData.append(`file`, item.blob);
// formData.append(`index`, item.flag);
// formData.append(`md5`, fileMd5);
// formData.append(`filename`, file.name);
// uploadFile(formData).then(res => {
// this.objData.uploadStart++;
// resolve(res);
// }).catch(err => {
// reject(err);
// })
// })
// }
// })
// Promise.allSettled(uploadList).then(res => {
// if (res.some(item => item.status == "rejected")) {
// //至少一个分片失败
// } else {
// let { md5, fileName } = this.objData;
// mergeFile({ md5, fileName }).then(res => {
// this.uploadCompleted = true
// })
// }
// })
})
}
},
//多线程获取md5唯一标识
getFileMd5(file) {
let that = this;
return new Promise(resolve => {
const worker = new Worker(new URL('@src/webWork/fileMd5.js', import.meta.url))
// 向子线程发消息
worker.postMessage(file)
// 接收子线程发来的消息
worker.onmessage = e => {
that.objData.md5 = e.data
resolve(that.objData.md5);
worker.terminate();
}
})
},
//开始切片
getSliceList(file) {
let result = [];
let index = 0;
for (let nowSize = 0; nowSize < file.size; nowSize += this.objData.chunkSize) {
result.push({
flag: index,
blob: file.slice(nowSize, nowSize + this.objData.chunkSize),
})
index++;
}
return result;
},
//判断之前是否上传过
hadUpload() {
let { fileName, md5 } = this.objData;
return new Promise((resolve, reject) => {
hadUploadFile({ fileName, md5 }).then(res => {
resolve(res);
}).catch(err => {
reject();
})
})
},
//并发控制
concurRequest(urls, maxNum){
let that = this
return new Promise(resolve => {
let index = 0; //指向下一次请求的Url对应的下标
let result = [] //保存请求的结果
let count = 0; //当前完成请求的数量
async function _request(){
let i = index
const url = urls[index]
index++;
try{
// const resp = await fetch(url)
const formData = new FormData();
formData.append(`file`, url.blob);
formData.append(`index`, url.flag);
formData.append(`md5`, that.objData.md5);
formData.append(`filename`, that.objData.fileName);
const resp = await uploadFileCopy(formData, 2)
console.log('请求结果', resp)
result[i] = resp
}catch(err){
result[i] = err
}finally{
that.objData.uploadStart++;
count++;
if(count == urls.length){
resolve(result)
}
if(index < urls.length){
_request()
}
}
}
for(let i = 0; i < Math.min(urls.length, maxNum); i++){
_request()
}
})
}
@src/webWork/fileMd5.js文件内容
// worker.js ---子线程
import SparkMD5 from "spark-md5"
// 接收主线程发来的消息
onmessage = (file) => {
// 向主线程发送消息
const reader = new FileReader();
reader.readAsArrayBuffer(file.data);
reader.onloadend = function (e) {
const spark = new SparkMD5.ArrayBuffer();
spark.append(e.target.result);
let md5 = spark.end();
postMessage(md5);
};
};
4.请求重试api
//请求重试
export const uploadFileCopy = (params, maxTimes) => {
let initTimes = 0;
let request = () => {
return postRequest("/file/upload", params, {"Content-Type": "multipart/form-data"}).catch(err => {
if(initTimes < maxTimes){
initTimes++
return request()
}else{
throw new Error('请求次数已达上限!')
}
})
}
return request()
}