uni.uploadfile 不支持并发控制,需手动实现限流;常见方案是按批次用 promise.all 并串行执行,如每批 3 个文件,避免 socket 关闭或卡死。

uni.uploadFile 本身不支持并发控制,必须自己实现队列或限流
uni.uploadFile 是个纯发起式 API,调用即发请求,没有任何内置的并发管理能力。它不会排队、不会限速、也不会自动重试。你看到的“并发上传”,全是靠 JS 层手动控制的——要么 Promise.all 一股脑全发,要么 for 循环里加 await 串行,或者用更精细的并发池。
常见错误现象:uploadFile:fail socket is closed 或 iOS 上直接卡死,基本都是没做并发限制,一次扔了 10+ 个大图上去,App 端扛不住;微信小程序虽有内部队列,但超过 10 个连接仍会拒绝新任务。
- 小程序平台(如
mp-weixin)底层有轻量级队列,但只对 success/fail 回调做顺序保证,不解决内存和网络拥塞 - App 平台(
app-plus)完全无队列,全靠你控速,否则容易触发系统级 socket 资源耗尽 - H5 平台走的是 form-data 模拟,本质是多个
XMLHttpRequest,浏览器自身有并发限制(通常 6~10 个),超了就排队
用 Promise.all + 并发数限制是最简可行方案
别被“Promise.all 是全并发”吓住——你可以先切片,再分批执行。比手写队列轻量,又比裸 for 循环高效。
核心逻辑就是:把 tempFilePaths 数组按每批 n 个切开,对每批用 Promise.all,再用 for...of 串行跑批次。
const concurrency = 3;
const uploadBatch = async (filePaths) => {
return Promise.all(
filePaths.map(filePath =>
new Promise((resolve, reject) => {
uni.uploadFile({
url: 'https://api.example.com/upload',
filePath,
name: 'file',
formData: { userId: '123' },
success: res => resolve(JSON.parse(res.data)),
fail: reject,
});
})
)
);
};
// 批量上传主函数
const uploadAll = async (tempFilePaths) => {
const results = [];
for (let i = 0; i
- 并发数建议设为 3~5:兼顾速度与稳定性,iOS App 和微信小程序都较友好
- 每个
Promise内必须捕获fail,否则一个失败会导致整批Promise.allrejected - 不要在
uploadFile外层套try/catch,它不抛异常,只走fail回调
H5 平台必须用 files 字段,filePath 完全无效
这是跨端最易翻车的点:H5 下传 filePath 会静默忽略,最终报 uploadFile:fail no file path,不是 bug,是设计如此。
正确做法是监听 <input type="file" multiple>,从 event.target.files 拿 File 对象,再喂给 files 字段。
-
filePath只在 App / 小程序端有效;H5 必须删掉它,否则上传逻辑会误判路径存在 -
files是数组,每个元素要带uri(File实例)、name(字段名)、fileName(建议显式传,避免后端收到blob) - 示例结构:
{ uri: file, name: 'file', fileName: file.name }
上传状态和错误处理常被跳过,但直接影响用户体验
只写 success 回调,等于放弃对失败的感知。用户点了上传按钮,界面没反应、没 loading、没 toast,大概率会重复点击,造成重复请求或数据错乱。
- 务必监听
onProgressUpdate:能拿到progress、totalBytesSent、totalBytesExpectedToSend,用于更新 UI 进度条 -
fail回调不能空着:至少记录日志,最好返回结构化错误(如网络断开、token 过期、文件超限) -
complete必须调用:无论成功失败,都要关掉 loading、释放资源、更新文件项状态(pending → done/error) - 临时路径(
tempFilePath)有生命周期:iOS 30 秒、Android 1 分钟、小程序约 1 小时,上传失败后若需重试,得重新选文件或缓存 File 对象(H5)











