uni.uploadFile 不支持跨平台实时进度回调,H5 也不生效;唯一可靠方案是 uni.request + ArrayBuffer 分片上传,需前后端协同支持分片协议,并用 Map 管理任务状态、防抖更新进度视图。

uni.uploadFile 本身不支持单次请求的实时进度回调
这是最常被误解的一点:很多人以为调用 uni.uploadFile 后传个 onProgressUpdate 就能拿到上传百分比,但实际上 H5 平台以外(如微信小程序、App)onProgressUpdate 是无效的;即使在 H5,它也只对 XMLHttpRequest 原生请求生效,而 uni.uploadFile 在 H5 底层封装的是 formdata + input[type=file] 提交,压根不走 XHR,所以根本不会触发该回调。
真正能稳定获取进度的唯一路径是——自己用 uni.request + ArrayBuffer 分片上传,并手动计算已上传字节数占比。
- 必须读取文件为
ArrayBuffer(用uni.getFileSystemManager().readFile或uni.chooseFile后的tempFilePath转 base64 再解码,但更推荐前者) - 后端需支持分片接收(比如接受
chunkIndex、totalChunks、fileId等字段) - 前端需维护每个文件的已上传 chunk 列表,失败要重试,避免重复上传同一片
批量任务需要用 Map 或数组管理独立生命周期
直接 for 循环扔一堆 uni.uploadFile 调用,会导致无法区分哪个进度属于哪个文件,也无法暂停/取消指定任务。正确做法是为每个上传项分配唯一 taskId,并用 Map 存储其状态:
const uploadTasks = new Map();
// 示例结构:
// uploadTasks.set('task_001', {
// fileId: 'xxx',
// fileName: 'a.jpg',
// totalSize: 2097152,
// uploadedBytes: 0,
// status: 'uploading', // 'pending' | 'uploading' | 'success' | 'failed'
// abortController: new AbortController() // 仅 H5 支持 abort
// });
- 每个任务的状态更新必须通过
uploadTasks.set(taskId, newState)同步,不能只改局部变量 - 微信小程序不支持
AbortController,取消任务只能靠后端配合「标记废弃」+ 前端忽略后续回调 - App 平台(iOS/Android)对并发数有限制(通常 6~10),需用队列控制,比如用
p-limit或手写串行调度器
进度条渲染必须防抖 + 节流,否则卡死 UI
分片上传时,每片成功就更新一次 uploadedBytes,如果每 KB 都触发 setData(小程序)或 this.$forceUpdate()(Vue),页面会明显卡顿甚至崩溃。实际只需保证每 200ms 最多刷新一次视图:
// Vue 3 setup 中示例
let pendingUpdate = false;
function scheduleUpdate() {
if (pendingUpdate) return;
pendingUpdate = true;
setTimeout(() => {
// 触发响应式更新(如 this.progressMap = new Map(this.progressMap))
pendingUpdate = false;
}, 200);
}
- 不要在每次分片回调里直接调用
this.$set或修改响应式对象深层属性 - 小程序中
setData有体积限制(1MB),上传大文件时建议只传关键字段:{ [`progress.${taskId}`]: percent },而非整个任务对象 - 进度数值建议保留一位小数,避免频繁触发相同值更新(如 33.3 → 33.3 不重绘)
微信小程序真机上 wx.uploadFile 的“伪进度”陷阱
部分开发者发现,在微信开发者工具里 onProgressUpdate 能打印日志,但真机完全不触发——这不是 bug,而是微信的策略:真机环境下为节省资源,默认禁用该回调,除非你在 project.config.json 中显式开启调试模式(仅限开发),且上线后必然失效。
- 别依赖
onProgressUpdate做核心功能,它只是开发辅助 - 真机验证必须用分片 +
uni.request方案,否则进度条永远显示 0% 或直接跳到 100% - 如果后端不支持分片,唯一妥协方案是:上传前预估时间(基于文件大小和历史平均网速),用定时器模拟进度,但用户感知差,且无法反映真实失败
分片上传的边界逻辑最容易出错:比如最后一片不足固定大小、MD5 校验时机、合并请求的幂等性处理。这些不是前端能绕开的,得和后端对齐协议细节,否则看似进度跑得欢,最终文件却损坏。











