uni-app 无原生批量上传接口,需通过多次调用 uni.uploadFile 实现,应避免 forEach 直接调用导致的并发失控、tempFilePath 失效及状态混乱问题,推荐用 Promise.allSettled 封装并限制并发数上传。

uni-app 没有真正的“批量上传”接口,uni.uploadFile 只支持单文件上传。所谓批量,本质是多次调用 uni.uploadFile —— 串行或并行,取决于你是否控制并发数。
为什么直接 forEach + uploadFile 会出问题
常见错误是写成这样:
this.selectedImages.forEach(path => {
uni.uploadFile({ filePath: path, url: '/upload' })
})
这会导致:iOS 上部分图片上传失败、状态混乱、progress 回调丢失、服务器收不到文件(传了路径字符串而非二进制流)、H5 和小程序行为不一致。
-
uni.uploadFile是异步但不返回 Promise(旧版),直接 forEach 不保证执行顺序,也无法统一捕获成功/失败结果 - 真机(尤其 iOS)的
tempFilePath生命周期极短,未及时上传就失效,再调用会报错 “file not found” - 并发太多(比如 9 张图同时上传)容易触发小程序限流或 App 端 socket 资源耗尽,表现为 pending 卡死或 400 错误
必须手动管理上传队列和状态
不能只存 tempFilePaths 字符串数组。要为每张图维护独立状态,包括原始路径、预览 URL、上传进度、结果标识。
- 定义结构:
images: [{ tempPath: '', url: '', status: 'ready' | 'uploading' | 'success' | 'fail', progress: 0 }] - H5 下
url可直接用tempFilePaths[i];小程序/App 需保持原路径(tempPath),<image>的src绑定item.tempPath即可渲染 - 每次
uni.chooseImage后,用map构造新数组赋值给images,避免响应式失效 - 删除某张图时,必须同步从
images数组中移除对应项,否则重复选择可能触发count限制误判
推荐用 Promise.allSettled 控制并发上传
不要裸写 for 循环或 forEach。用 Promise.allSettled 包裹每个 uni.uploadFile 调用,能统一收集结果、避免竞态、方便重试。
- 先封装一个返回 Promise 的上传函数:
const uploadOne = (filePath) => {
return new Promise((resolve) => {
uni.uploadFile({
url: '/api/upload',
filePath,
name: 'file',
header: { 'Authorization': 'Bearer xxx' },
success: (res) => resolve({ status: 'fulfilled', data: res.data }),
fail: (err) => resolve({ status: 'rejected', error: err })
})
})
}
- 再限制并发数(例如最多 3 个并发):
const uploadBatch = async (paths) => {
const results = []
for (let i = 0; i < paths.length; i += 3) {
const batch = paths.slice(i, i + 3)
const batchResults = await Promise.allSettled(batch.map(uploadOne))
results.push(...batchResults)
}
return results
}
这样既避免卡死,又能拿到每张图的明确结果(成功/失败/原因),便于更新 images 中对应项的 status。
最易被忽略的一点:iOS 的 tempFilePath 有效期以毫秒计,一旦 chooseImage 完成,就得立刻开始上传逻辑——哪怕只是 push 到队列里。缓存路径字符串超过 1 秒再调用 uploadFile,大概率失败。


















