使用Promise.allSettled发起大量请求时如何避免阻塞其他新请求
解决方案
问题根因
你遇到的阻塞本质是浏览器对同域名的最大并发请求数限制(Chrome/Edge等主流浏览器默认是6个),你一次性发起100个请求时,剩下94个请求会进入浏览器的请求队列排队,此时用户触发的新请求(比如retriveUserDetail)也会排在队列末尾,等轮到它的时候早就超过10s的前端超时时间,自然会被取消。
另外你的代码有个常见误区:循环中直接调用createParticipant时请求就已经发出了,Promise.allSettled只是用来等待所有请求的结果,不是控制请求发起的时机。
可行优化方案
1. 批量请求并发数控制(最推荐)
不要一次性发起全部100个请求,限制批量任务的同时请求数(建议设为34,预留23个空位给用户主动触发的高优先级请求),就能从根本上避免队列阻塞。
以下是并发控制的实现代码:
// 并发控制工具函数,limit是最大同时请求数 const concurrentRun = async (tasks, limit = 3) => { const results = [] const executing = [] for (const task of tasks) { // 包装任务,执行完后从执行队列移除 const p = Promise.resolve().then(task) results.push(p) executing.push(p) const clean = () => executing.splice(executing.indexOf(p), 1) p.then(clean, clean) // 执行队列满了就等任意一个请求完成再进下一个 if (executing.length >= limit) { // 每批完成后留50ms空隙处理其他用户请求 await Promise.race(executing) await new Promise(resolve => setTimeout(resolve, 50)) } } return Promise.allSettled(results) } // 改造你的批量创建逻辑 // 注意:这里要先把请求包装成函数,不要直接调用,否则还是会一次性发请求 const taskList = [] for (let i = 0; i < totalNumber; i++) { const participant = participantList[i] const participantNewDetail = { firstName: participant.firstName, lastName: participant.lastName, email: participant.email, } // 包装成函数,执行时才发起请求 taskList.push(() => createParticipant(participantNewDetail) .then((createParticipantResult) => { processedTask++ processMessage = `Processing adding participant` dispatch({ type: ACTIVATE_PROCESS_PROCESSING, payload: { processedTask, processMessage } }) }) .catch((error) => { processedTask++ processMessage = `Processing adding participant` dispatch({ type: ACTIVATE_PROCESS_PROCESSING, payload: { processedTask, processMessage } }) throw new Error( JSON.stringify({ status: "failed", value: error.data.message ? error.data.message : error, }) ) }) ) } // 限制最多3个并发执行批量请求 const addParticipantResults = await concurrentRun(taskList, 3)
2. 拆分请求优先级
- 拆分两个axios实例:交互类请求(用户主动点击触发的查询、操作)用一个实例,保持10s超时;批量后台任务用另一个实例,超时设为20s和后端匹配,避免批量请求提前失败。
- 如果有高优先级请求发起时,可以主动暂停批量任务的执行,等高优先级请求完成后再恢复批量任务,体验会更流畅。
3. 后端接口优化(可选)
如果业务允许,后端可以新增一个批量创建参与者的接口,前端一次性传100条数据,只需要发起1次POST请求,完全不存在并发阻塞问题,性能也会高很多。
关于拆分小批量请求的疑问
完全可以拆成多个小数组分批发送,上述并发控制方案本质就是自动分批的逻辑,你也可以手动按10个一组拆分,每执行完一组就留100ms的空闲窗口处理其他请求,效果是一样的。
内容的提问来源于stack exchange,提问作者Moon
相关产品推荐
相关产品推荐

