前端批量请求的并发控制与工程化实践

在上一篇文章中,我们已经完成了数据准备工作。本篇将重点介绍一个在真实业务中几乎绕不开的问题

当需要对一组数据逐个请求接口时,如何优雅、安全地进行批量请求?

如果处理不当,轻则页面卡顿,重则接口被限流甚至封禁。


一、为什么不能直接 Promise.all

最常见的写法是这样:

ini 复制代码
Promise.all(
  list.map(item => request(item))
);

这个写法的问题在于:

  • 并发数量 不可控

  • 列表一长就会:

    • 打满浏览器并发
    • 压垮后端服务
  • 一旦某个请求失败,整体直接 reject

在区县、设备、用户、文件等数量不确定的场景下,这种方式风险极高。


二、我们真正需要的是什么?

一个成熟的「批量请求」方案,至少应该满足:

  1. 限制并发数量
  2. 支持批次间隔(节流)
  3. 单个失败不影响整体流程
  4. 能够感知整体完成状态
  5. 结果和错误可以分开统计

三、核心设计思路

1️⃣ 把"请求"和"执行"解耦

  • 批量工具只负责 调度
  • 具体请求由调用方传入
javascript 复制代码
(task) => Promise

2️⃣ 固定并发数,分批执行

  • 每一批最多 N 个任务
  • 当前批次完成后,延迟一段时间再执行下一批

3️⃣ 所有任务最终返回一个统一结果

ini 复制代码
{
  results: [],
  errors: []
}

四、批量请求使用方式(示例)

下面是一个典型的使用方式:

javascript 复制代码
this.batchRequestWithLimit(
  taskList,
  (task) => {
    return apiRequest(task);
  },
  (task, data) => {
    console.log(`任务 ${task} 成功`, data);
  },
  5,   // 最大并发数
  200, // 批次间隔(ms)
)
  .then(({ results, errors }) => {
    console.log(
      `批量请求完成:成功 ${results.length} 个,失败 ${errors.length} 个`
    );
  })
  .catch(err => {
    console.error("批量请求异常:", err);
  });

从使用者视角看,这个方法具备:

  • 调用简单
  • 参数语义清晰
  • 结果可控

五、执行流程拆解(非常关键)

整个批量请求的生命周期可以拆成 5 步:

Step 1:任务队列初始化

ini 复制代码
const queue = [...taskList];

Step 2:取出当前批次

ini 复制代码
const batch = queue.splice(0, limit);

Step 3:并发执行当前批次

ini 复制代码
await Promise.allSettled(
  batch.map(task => executor(task))
);

Step 4:等待节流时间

scss 复制代码
await sleep(interval);

Step 5:继续下一批,直到队列清空


六、为什么 Promise.allSettled 是关键

相比 Promise.all

方法 任一失败 结果可控
Promise.all ❌ 整体失败
Promise.allSettled ✅ 单独失败

批量请求场景中

失败是常态,而不是异常

我们要做的是:

  • 接受失败
  • 记录失败
  • 不中断流程

七、这种模式适合哪些场景?

这种批量请求模型,适用于:

  • 区县 / 城市 / 设备 / 用户 批量拉取
  • 文件批量上传 / 下载
  • 批量校验、扫描、统计
  • 任何「数量不确定 + 接口有压力」的业务场景

八、总结一句话

批量请求不是"多发请求",而是"有节制地并发执行任务"。

通过:

  • 限制并发
  • 分批执行
  • 错误隔离
  • 统一收敛结果

你可以把一个"危险操作",变成一个可控、可扩展、可维护的工程能力

相关推荐
destinying13 分钟前
性能优化之实战指南:让你的 Vue 应⽤跑得飞起
前端·javascript·vue.js
晴殇i2 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
BER_c2 小时前
前端权限校验最佳实践:一个健壮的柯里化工具函数
前端·javascript
敲敲敲敲暴你脑袋3 小时前
写个添加注释的vscode插件
javascript·typescript·visual studio code
SuperEugene3 小时前
后台权限与菜单渲染:基于路由和后端返回的几种实现方式
前端·javascript·vue.js
csdn飘逸飘逸3 小时前
Autojs基础-全局函数与变量(globals)
javascript
KKKK3 小时前
手写Promise,从测试用例的角度理解
javascript
青青家的小灰灰3 小时前
迈向全栈新时代:SSR/SSG 原理、Next.js 架构与 React Server Components (RSC) 实战
前端·javascript·react.js
SuperEugene3 小时前
弹窗与抽屉组件封装:如何做一个全局可控的 Dialog 服务
前端·javascript·vue.js
青青家的小灰灰3 小时前
透视 React 内核:Diff 算法、合成事件与并发特性的深度解析
前端·javascript·react.js