Promise.all + uni.request 在 App 端会静默丢弃请求,因原生层(WKWebView/X5)限制并发连接数,导致部分请求不发出、不报错;应使用 p-limit 或手写队列限流至 6–8 个并发。

Promise.all + uni.request 在 App 端大概率漏数据,不是“失败”,而是“静默丢弃”——尤其 iOS 和 Android X5 内核下,超过 6–10 个并发请求时,部分 uni.request 根本不发出去,也不报错、不进 fail 回调。
为什么 Promise.all 会出问题
根本原因不是 JavaScript 层的问题,而是 uni.request 最终委托给原生容器发起网络请求,而原生层(WKWebView / X5)对并发连接数做了硬性限制。常见现象包括:
-
Promise.all返回的数组里某些项是undefined或空对象,但控制台无任何错误 - DevTools 的 Network 面板完全看不到对应请求记录(尤其 iOS)
- 同一组 URL,在 H5 正常,App 端固定从第 7 个开始“消失”
- 响应时间忽长忽短,且没有规律可循
用 p-limit 主动限流(推荐)
必须绕过 Promise.all 的“全量并发”行为,改用节流器控制同时最多执行几个 uni.request。安装后直接用:
npm install p-limit
代码示例:
import pLimit from 'p-limit';
const limit = pLimit(6); // 同时最多 6 个
const urls = ['https://api.a', 'https://api.b', 'https://api.c'];
const promises = urls.map(url =>
limit(() => uni.request({ url }))
);
const results = await Promise.all(promises);
注意点:
- 不要把
limit()放在封装好的request()函数内部——那会让限流逻辑被多层嵌套覆盖 - 数值设为 6 是较稳妥的起点,iOS WKWebView 实测稳定上限通常就是 6;Android X5 可尝试 8,但需实测验证
-
p-limit不会改变 Promise 顺序,results下标与urls严格对应
手写队列(零依赖方案)
如果不想加 npm 包,可用以下轻量队列函数,按批次分批执行:
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())));
}
return results;
}
// 使用方式
const requests = urls.map(url => () => uni.request({ url }));
const results = await runInLimit(requests, 6);
关键细节:
- 每次
Promise.all只处理limit个任务,避免底层并发超限 - 返回的是扁平数组(不是二维),和原始
urls顺序一致 - 若某次 batch 中有请求失败,整个
Promise.all会 reject,需在外层加try/catch
封装 request 时最容易踩的坑
如果你已封装了统一的 request 方法,务必避开这三个典型错误:
- 不在封装函数里直接
return Promise.all([...])——这等于把压力又甩回原生层 - 避免在
success回调里再调一次uni.request并塞进同一个Promise.all,嵌套会指数级放大并发数 -
uni.addInterceptor对并发控制无效(它只拦截单个请求生命周期,不干预调度)
真正起作用的,永远是「在触发请求前就控制数量」,而不是等 uni.request 自己去扛。


















