获取上传进度的几种方式

获取上传进度的几种方式

今天测试说咱们的上传后的等待界面都没有loading, 看起来不像是等待界面需要优化。然后产品说参考下其他业务的上传搞下吧。 我以为就一个loading的事,发现其他业务上传使用的是环形、线形进度条。我说现在接口是没有返回当前进度的,如果是以上传完成后的文件数量(因为我们是一个个文件上传分批次调的接口)做判断也不太准确,因为文件有大有小的。

后面就找另外一个前端同事聊了下他告诉我说axios是有监听整个上传进度api的,那我就针对文件上传去了解了下做以下总结:

前端使用axios实现监听上传进度

咱们先使用axios实现监听上传进度如下:

js 复制代码
axios.post('/api/file/uploadfile', form, {
  headers: {
    'Content-Type': 'multipart/form-data',
  },
  onUploadProgress: (progressEvent) => {
    if (progressEvent.lengthComputable) {
      this.progresss = Math.round((progressEvent.loaded / progressEvent.total) * 100);
    }
  },
})
  .then((res) => {
   // ...
  });

前端使用ajax获取上传进度

前端使用ajax如何获取上传进度呢? 如下:

js 复制代码
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (event) => {
  if (event.lengthComputable) {
    const progressPercentage = Math.round((event.loaded / event.total) * 100);
    console.log(`上传进度: ${progressPercentage}%`);
  }
});

前端使用fetch API获取上传进度

如何使用fetch API获取上传的进度呢?如下:

js 复制代码
const file = document.getElementById('fileInput').files[0];

fetch('/upload', {
  method: 'POST',
  body: file,
  onprogress: (event) => {
    if (event.lengthComputable) {
      const progressPercentage = Math.round((event.loaded / event.total) * 100);
      console.log(`上传进度: ${progressPercentage}%`);
    }
  },
})
  .then((response) => {
    // 处理响应结果
  })
  .catch((error) => {
    // 处理错误
  });

上面几种都是获取上传进度展示的进度条。那么咱们还有那些展示进度条的方式呢?

多文件上传展示一个进度条

如果支持多个文件上传,并已文件上传个数展示进度条的话,一般都是怎么做的呢?

  • 需要考虑多个文件比如10个文件,在你上传完第一个的时候进度条需要控制再10%以下,依此类推。如下面一块代码:
js 复制代码
let progress = 0;
const UPLOAD_TYPE_MAP = {
  UPLOADING: 'uploading',
  COMPLATE: 'complate',
}
const files = [{ file:'', status: UPLOAD_TYPE_MAP.UPLOADING }, { file:'', status: UPLOAD_TYPE_MAP.UPLOADING }];

for (let index = 0; index < files.length; index++) {
  const element = files[index];
  // 1、这里是调接口的逻辑,可以是并行也可以完成一个调下一个,这个看你们的接口的限速吧,我就按照并行做了。
  // 2、这里是每个文件上传完成的逻辑,更改当前文件的状态把status 改成UPLOAD_TYPE_MAP.COMPLATE
}

const timer = setInterval(() => {
  const eachProgress = 100 / files.length; // 计算单个的比例
  const complateUpload = files.filter((item) => item.status === UPLOAD_TYPE_MAP.COMPLATE);
  const upperLimit = (complateUpload.length + 1) * eachProgress;
  const maxProgress = upperLimit > 100 ? 100 : upperLimit; // 计算出当前最大进度

  if(progress < maxProgress) {
    progress++; // 边界控制
  }
  if(maxProgress === 100) {
    progress = 100;
    clearInterval(time);
  }
}, 500);

上面就多文件展示一个进度条的具体代码。其实不是很准确,文件有大有小,如果文件大小差不太多展示开可以。其实最好的方案是分别利用axiosajax等分别展示一个进度条。还是看业务需求吧,

大文件分片上传展示进度条

先简单说下分片上传的好处如下:

  1. 可靠性和鲁棒性:将大文件分成小块进行上传,即使出现网络中断或其他意外情况,只需要重新上传失败的分片,而不需要重新上传整个文件,提高上传的可靠性和鲁棒性。

  2. 传输效率:由于大文件被分成多个小块进行并行上传,可以充分利用网络带宽,提高传输速度和效率。

  3. 断点续传:如果上传过程中断,可以根据已成功上传的分片信息,从上次中断的地方继续上传,避免重复上传已经上传过的部分,节省时间和资源。

  4. 内存占用低:大文件一次性加载到内存中可能导致内存溢出,而分片上传只需加载单个分片,减少了对内存的压力,并适应内存有限的环境。

  5. 服务器负载平衡:使用分片上传可以将上传请求分散到多个服务器,降低单一服务器的负载压力,提高整体系统的稳定性和吞吐量。

  6. 灵活性:分片上传允许用户在任意时间暂停、取消或恢复上传过程,提供了更好的用户体验和操作灵活性。

其实像咱们经常说别的网站为啥有的上传速度这么快,我用的网速一样我的为啥这么慢。其实还有就是看你们上传的文件大小有没有必要做分片上传,毕竟没有直接一个接口上传开发快,前端、服务端都需要增加工作成本。那咱们下面先看下怎么实现分片如下:

js 复制代码
// 定义分片大小(以字节为单位) // 1MB

// 将文件切割为多个分片
function sliceFileIntoChunks(file, chunkSize = 1024 * 1024) {
  const fileSize = file.size;
  const chunks = Math.ceil(fileSize / chunkSize);
  const fileChunks = [];
  let start = 0;
  let end = chunkSize;

  for (let i = 0; i < chunks; i++) {
    const chunk = file.slice(start, end); // slice 可以把文件按照需要的大小分割
    fileChunks.push(chunk);

    start = end;
    end = start + chunkSize;
  }

  return fileChunks;
}

获取上传进度(这个需求又回到了【多文件上传展示一个进度条】上面)如下:

js 复制代码
const files = sliceFileIntoChunks(originFile).map((item) => ({file: item, status: UPLOAD_TYPE_MAP.UPLOADING}));

// ... 忽略
const timer = setInterval(() => {
  const eachProgress = 100 / files.length; // 计算单个的比例
  const complateUpload = files.filter((item) => item.status === UPLOAD_TYPE_MAP.COMPLATE);
  const upperLimit = (complateUpload.length + 1) * eachProgress;
  const maxProgress = upperLimit > 100 ? 100 : upperLimit; // 计算出当前最大进度

  if(progress < maxProgress) {
    progress++; // 边界控制
  }
  if(maxProgress === 100) {
    progress = 100;
    clearInterval(time);
  }
}, 500);

有一个点需要注意你要告诉服务端你得切片索引,后面服务端还要合并切片呢!!! 。还有如果你们是按照大小切割的比如1M,你还要再上传完成给服务端发送一个合并切片的通知。 如果你们是以份额切分的每次就分为10等份,那么这个上传完成的请求你不再通知服务端也能判断上。

结语

以上就是几种上传进度条的解决方案,希望对您有帮助,欢迎点赞收藏。如果您还做过其他场景的进度条展示可以把实现方案放在评论区咱们一起探讨。

相关推荐
web1309332039819 分钟前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
王小王和他的小伙伴22 分钟前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱26 分钟前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿31 分钟前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08211 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光931 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
隐形喷火龙1 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_748241122 小时前
Selenium之Web元素定位
前端·selenium·测试工具
风无雨2 小时前
react杂乱笔记(一)
前端·笔记·react.js
前端小魔女2 小时前
2024-我赚到自媒体第一桶金
前端·rust