JavaScript实现大文件上传的示例代码

作者:freeman_Tian 时间:2024-05-28 15:40:23 

下面就是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
       }

来源:https://segmentfault.com/a/1190000042838969

标签:JavaScript,大文件,上传
0
投稿

猜你喜欢

  • 全面阐述overflow:hidden属性

    2008-08-18 13:30:00
  • 常见的python正则用法实例讲解

    2023-03-11 23:11:29
  • JavaScript中的ArrayBuffer详细介绍

    2024-04-19 11:02:13
  • 参考sql2012存储过程写的统计所有用户表尺寸大小的示例

    2024-01-25 05:50:18
  • 剖析网页设计中的几何圆

    2010-10-19 12:27:00
  • my.ini优化mysql数据库性能的十个参数(推荐)

    2024-01-25 13:06:56
  • python各种excel写入方式的速度对比

    2021-04-23 22:30:15
  • ibatis简单实现与配置

    2023-03-07 20:33:17
  • python爬虫爬取网页表格数据

    2023-06-04 08:23:14
  • Python排序搜索基本算法之堆排序实例详解

    2021-07-10 12:35:30
  • 详解Python中的自定义密码验证

    2021-06-05 00:38:59
  • php下防止单引号,双引号在接受页面转义的设置方法

    2023-11-15 02:37:01
  • Python实现Appium端口检测与释放的实现

    2023-03-08 08:34:23
  • 教你用python提取txt文件中的特定信息并写入Excel

    2021-02-11 00:41:41
  • MYSQL随机抽取查询 MySQL Order By Rand()效率问题

    2024-01-28 03:01:30
  • MySQL跨服务器数据映射的实现

    2024-01-23 15:08:19
  • Python实现随机划分图片数据集的示例代码

    2021-08-01 16:35:32
  • Python 实现局域网远程屏幕截图案例

    2021-05-13 13:43:43
  • pyqt5 QScrollArea设置在自定义侧(任何位置)

    2023-05-22 09:33:51
  • 如何解决springboot数据库查询时出现的时区差异问题

    2024-01-26 01:53:01
  • asp之家 网络编程 m.aspxhome.com