Skip to content

上传进度

实现思路

  1. 使用 XMLHttpRequestFetch API 进行文件上传。
  2. 监听上传过程中的进度事件。
  3. 计算上传百分比,并更新进度条。

代码示例

XHR

progress 事件对象属性:

  • lengthComputable:指示是否可以计算总字节数的布尔值,如:true
  • loaded:已上传的字节数。
  • total:文件总字节数(如果可计算)。

计算进度:percentComplete = (loaded / total) * 100

js
const fileInput = document.getElementById('fileInput')

fileInput.addEventListener('change', (event) => {
  const file = event.target.files[0]
  if (!file) return

  const xhr = new XMLHttpRequest()
  xhr.open('POST', '/upload-endpoint') // 替换为实际的上传端点

  xhr.upload.addEventListener('progress', (event) => {
    if (event.lengthComputable) {
      const percentComplete = (event.loaded / event.total) * 100 // 计算上传百分比
      console.log(`Upload progress: ${percentComplete.toFixed(2)}%`)
    }
  })

  xhr.onload = () => {
    if (xhr.status === 200) {
      console.log('上传完成', xhr.responseText)
    } else {
      console.error('上传失败', xhr.statusText)
    }
  }

  const formData = new FormData()
  formData.append('file', file)
  xhr.send(formData)
})

Fetch

原生 Fetch API 不支持上传进度监听。

Axios

由于 Axios 底层使用 XMLHttpRequest,因此支持上传进度监听。

js
const fileInput = document.getElementById('fileInput')

fileInput.addEventListener('change', (event) => {
  const file = event.target.files[0]
  if (!file) return

  const formData = new FormData()
  formData.append('file', file)

  axios
    .post('/upload-endpoint', formData, {
      onUploadProgress: (progressEvent) => {
        const percentComplete = (progressEvent.loaded / progressEvent.total) * 100
        console.log(`Upload progress: ${percentComplete.toFixed(2)}%`)
      },
    })
    .then((response) => {
      console.log('上传完成', response.data)
    })
    .catch((error) => {
      console.error('上传失败', error)
    })
})

上传进度常见问题

为什么进度条卡在了 99% 不动了?

原因:progress 事件只反映上传进度,不包括服务器处理时间。

最佳实践:将进度条上传进度压缩为 0-90%,剩余 10% 用于服务器处理时间。

progress 事件频繁触发,影响性能怎么办?

可以考虑使用 throttle 降低事件触发频率,例如每 200ms 更新一次进度条。

js
import { throttle } from 'lodash'

const handleProgress = throttle((event) => {
  if (event.lengthComputable) {
    const percentComplete = (event.loaded / event.total) * 100
    console.log(`Upload progress: ${percentComplete.toFixed(2)}%`)
  }
}, 200)

xhr.upload.addEventListener('progress', handleProgress)

基于 MIT 许可发布