获取上传进度的几种方式

获取上传进度的几种方式

今天测试说咱们的上传后的等待界面都没有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等份,那么这个上传完成的请求你不再通知服务端也能判断上。

结语

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

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax