Promise.all在App端漏请求是因为uni.request受限于原生容器并发连接数(iOS/Android通常6–10),超限请求被静默丢弃;需用p-limit或手写分批队列控制并发,限流必须作用于uni.request调用前且统一入口。

uni-app里Promise.all为什么在App端会漏请求
因为uni.request不是浏览器原生fetch,它最终走的是原生容器的网络层,而 iOS WKWebView 和 Android X5 内核对并发连接数有硬限制(通常 6–10 个)。Promise.all本身不控制并发,只是同步触发所有uni.request,超出限制的请求会被静默丢弃——不进success、不进fail、DevTools Network 面板里也看不到记录。
常见表现包括:
-
Promise.all返回数组中某几项是undefined或空对象 - 同一组 URL,在 H5 正常,App 端固定从第 7 个开始“消失”
- 响应时间忽长忽短,且无错误抛出
用p-limit做轻量并发控制
npm 安装后直接封装调用,比手写队列更稳,支持取消、限流复用等扩展能力。
必须注意三点:
- 限流粒度要落在
uni.request调用前,不能包在封装好的 request 函数内部再套Promise.all -
p-limit(6)里的 6 是建议值,iOS 实测建议 ≤5,低端安卓可放宽到 8 - 不要把
limit(() => uni.request(...))写成limit(() => this.$http.get(...))——如果封装层又做了重试或拦截,可能放大并发数
const pLimit = require('p-limit');
const limit = pLimit(6);
const promises = urls.map(url =>
limit(() => uni.request({ url, method: 'GET' }))
);
const results = await Promise.all(promises);
手写分批队列(零依赖方案)
适合不想引入额外包、或需深度定制进度/重试逻辑的场景。核心是「按块切任务 + 每块内并行 + 块间串行」。
关键细节:
- 每批大小建议设为
6,避免 iOS 下首批就超限 - 不要用
for await...of遍历批数组——它本质仍是串行等待,无法释放并发收益 - 每批的
Promise.all仍需配合.catch(() => null)兜底,否则整批失败会导致后续批次不执行
async function runInLimit(tasks, limit = 6) {
const results = [];
for (let i = 0; i < tasks.length; i += limit) {
const batch = tasks.slice(i, i + limit);
results.push(
await Promise.all(batch.map(t => t().catch(() => null)))
);
}
return results.flat();
}
const requests = urls.map(url => () => uni.request({ url }));
const results = await runInLimit(requests, 6);
uniCloud.uploadFile同样不能直塞Promise.all
uniCloud.uploadFile和uni.request一样,底层走平台原生上传通道,微信小程序限流≤3,iOS 更敏感。直接Promise.all包裹多个上传,大概率出现「进度条卡住」「回调不触发」「部分文件根本没上传痕迹」。
必须做的动作:
- 上传并发上限设为
3,H5 环境下还要额外判断Blob是否已转为ArrayBuffer再进队列 - iOS 必须在
uniCloud.uploadFile调用前注册onUploadProgress,晚了就收不到回调 - 不要在
success里立即发起下一个uploadFile并塞进同一个Promise.all——这等于递归加压,并发数指数级膨胀
uni.request或uniCloud.uploadFile的那一层,且每处调用都走同一套控制入口,否则随便一个封装函数绕开限流,整套机制就失效。


















