JavaScript实现大文件上传的示例代码
freeman_Tian 人气:0下面就是JavaScript实现大文件上传功能的代码
bigFileUpload.js
const path = require('path') import axios from 'axios' import { resolve } from 'path'; import { promised } from 'q'; // 递归调用请求 async function dg(requestMargreList, options, key = 0) { let index = key const requestList = requestMargreList[key].map(({ formData }) => { return multipartUploadUpload(formData, options) } ); const resArr = await Promise.all(requestList); let boolean = resArr.every(item => item?.data?.status == 'SUCCEED') if(boolean){ index++ if(index == requestMargreList.length) { return {uploadFlag: true, msg: '上传切片文件成功' } } return dg(requestMargreList, options, index) } else { const res_err = resArr.map(item => item?.data?.status != 'SUCCEED') return {uploadFlag: false, msg: '切片文件上传出错,请重新尝试' } } } // 文件切片 function createFileChunk(file, size){ let fileChunkList = []; let cur = 0; while (cur < file.size) { fileChunkList.push({file:file.slice(cur, cur + size)}) cur += size; } return fileChunkList } function calculateHash(fileChunkList, container,options ={}) { return new Promise(resolve => { // 添加 worker 属性 container.worker = new Worker("/static/hash.js"); container.worker.postMessage({ fileChunkList }); container.worker.onmessage = e => { const { percentage, hash } = e.data; // 总进度变化 // hashPercentage = percentage; options.showHash(percentage) if (hash) { resolve(hash); } }; }) } function getMultipartLogId(params){ return new Promise(resolve =>{ axios.post('api/multipartUploadInit',params) .then(res=>{ resolve(res) }) }) } let globalPercentage = 0; function multipartUploadUpload(formData, options) { return axios.post('api/multipartUploadUpload',formData,{ onUploadProgress: function (upEvent) { // 文件上传总进度 let percentage = ((options.size * (formData.get('chunkIndex')- 1) + upEvent.loaded) / options.fileSize)*100 //options.size为分片后每片的大小 options.fileSize为文件总大小 percentage为计算后总进度 if(percentage > globalPercentage){ globalPercentage = percentage; } if(globalPercentage>100) globalPercentage = 100; options.showFileProgress(globalPercentage) } }) } async function uploadChunks(fileChunkList, options) { let reqMargeArr = [], reqSize = 3, uploadResObj = {}; let reqBeforeList = fileChunkList.map(({ multipartLogId,hash,file,fileName,chunkIndex }) => { const formData = new FormData(); formData.append("multipartLogId", multipartLogId); formData.append("hash", hash); formData.append("file", file); formData.append("fileName", fileName); formData.append("chunkIndex", chunkIndex); return { formData }; }) if(reqBeforeList.length > reqSize) { for (let i = 0; i < reqBeforeList.length; i += reqSize) { reqMargeArr.push(reqBeforeList.slice(i, i + reqSize)) } const {uploadFlag, msg} = await dg(reqMargeArr, options,) uploadResObj = { uploadFlag, msg} } else { const requestList = reqBeforeList.map(({ formData }) => { return multipartUploadUpload(formData, options) }); let resArr = await Promise.all(requestList); const uploadFlag = resArr.every(item => item?.data?.status == 'SUCCEED') uploadResObj = { uploadFlag, msg: uploadResObj.uploadFlag?'上传切片文件成功':'切片文件上传出错,请重新尝试'} } if(uploadResObj.uploadFlag) { // completeFunc函数中有回调接口判断是否合并成功 setTimeout(()=>{ completeFunc(fileChunkList[0].multipartLogId,options) }, 1000) } else { return uploadResObj } } function completeFunc(multipartLogId, options) { return axios.post('api/multipartUploadComplete',{multipartLogId}) .then(res=>{ options.completeFunc(res) }) } async function bigFileUpload(file, options={},fileOptions) { let container = {} let fileChunkList = createFileChunk(file,options?.size); const fileHash = await calculateHash(fileChunkList, container,options); fileOptions.hash = fileHash const upFileParams = await getMultipartLogId(fileOptions) // 删除已上传的文件片 let fileChunkListArr = []; let percentage = 0; if(upFileParams.data.status == 'SUCCEED'){ let chunkIndexs = upFileParams?.data?.data?.chunkIndexs; if(chunkIndexs?.length>0){ fileChunkList.map(({ file },index) => { if(!chunkIndexs.includes(index+1)){ fileChunkListArr.push({ multipartLogId: upFileParams.data.data.multipartLogId, chunkIndex: index + 1, hash: fileHash, file: file, fileName: fileOptions.fileName, }) } }); percentage = percentage + (chunkIndexs.length * fileOptions.chunkSize / options.fileSize)*100 options.showFileProgress(percentage) } else { fileChunkList.map(({ file },index) => { fileChunkListArr.push({ multipartLogId: upFileParams.data.data.multipartLogId, chunkIndex: index + 1, hash: fileHash, file: file, fileName: fileOptions.fileName, }) } ); } if(fileChunkListArr.length>0){ // 上传文件切片 const uploadRes = await uploadChunks(fileChunkListArr, options,percentage) return uploadRes } else { completeFunc(upFileParams.data.data.multipartLogId,options) } } else { return { uplodFlag: false, msg: upFileParams.data.extMessage } } } export default bigFileUpload
import bigFileUpload from './components/bigFileUpload' // 大文件上传 // 分片大小 bigFileUpload let fileParams = { size: bigSize, // 切片大小 fileSize: fileTem.size, showHash: this.showHash, showFileProgress: this.showFileProgress, completeFunc: this.completeFunc, } this.fileOptions = fileOptions const res = await bigFileUpload(fileTem, fileParams,fileOptions) console.log("=====big up res========", res) if(res && !res.uplodFlag) { _this.$Notice.error({ title: '提醒', desc: res.msg }) return }
加载全部内容