JavaScript实现大文件上传的示例代码
作者:freeman_Tian 发布时间:2024-05-28 15:40:23
标签:JavaScript,大文件,上传
下面就是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


猜你喜欢
- 一:直接把MDB(MDE)文件放到网络中的共享目录中,在客户端做好对应的快捷方式二:数据库折分(菜单:工具,实用工具,折分)成前后台,把后台
- 沟通的时候,一般我不主动说自己是做用户体验设计,也不说做以用户为中心的设计,包括UED, UCD。这种专业名词传达的太虚,你也许是名用户体验
- python安装教程和Pycharm安装详细教程,分享给大家。首先我们来安装python1、首先进入网站下载:点击打开链接(或自己输入网址h
- 购物车是电子商务网站中不可缺少的组成部分,但目前大多数购物车只能作为一个顾客选中商品的展示,客户端无法将购物车里的内容提取出来满足自己事务处
- Heroku是一个很棒的平台,它有很多的控件,并且搭建环境相对来说也比较容易。本指南中,我将一步一步指导你在Heroku平台上部署一个简单地
- 这次,我们再来用Ursina引擎来做一个太阳系行星模拟器吧!想要了解Ursina 3D引擎的基本使用方法的话,查看我的另一篇文章:详解Pyt
- 本文实例讲述了Flask框架中request、请求钩子、上下文用法。分享给大家供大家参考,具体如下:request就是flask中代表当前请
- 从CNNIC在2009年的报告中可以看到,超过80%的网民购物之前都要看评论(包括本站、其他站评论),超过80%的网民都比较信任口碑(包括网
- golang 的fmt 包实现了格式化I/O函数,类似于C的 printf 和 scanf定义示例类型和变量type Human struc
- 引言在 Linux 服务器上,磁盘空间的使用情况是一个非常重要的指标。如果服务器上的磁盘空间不足,可能会导致服务器崩溃,影响网站的正常运行。
- Pytorch如何完成多分类多分类问题在最后的输出层采用的Softmax Layer,其具有两个特点:1.每个输出的值都是在(0,1);2.
- 一、前提解决ES5中只有全局作用域和函数作用域,没有块级作用域而带来的不合理的场景。let基本用法用法和var 一样,只是let声明的变量只
- Blog的全名应该是Web log,中文意思是“网络日志”,后来缩写为Blog,而博客(Blogger)就是写Blog的人。从理解上讲,博客
- pytorch geometric的GNN、GCN节点分类# -*- coding: utf-8 -*-import osimport to
- 今天在公司,经理让做一个滚动字幕。但是,不许生成gif图片。所以上网找了GIFEncoder这个类库。确实很好用,但是,应用过程中也出现了一
- 运行下列脚本,可以打印出模型各个节点变量的名称:from tensorflow.python import pywrap_tensorflo
- 下面的代码使用正则表达式验证输入格式包括了验证邮箱和验证手机号码package com.firewolf.utils;import java
- 新安装的MySQL5.7,登录时提示密码错误,安装的时候并没有更改密码,后来通过免密码登录的方式更改密码,输入update mysql.us
- 起因是这样的,有一张表存在慢sql,查询耗时最多达到12s,定位问题后发现是由于全表扫描导致,需要对字段增加索引,但是表的数据量600多万有
- 1. ES6的新特性 允许将对象或者数组'分解'成多个单独的值, 以对象的解构开始. &