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

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

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

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


一、为什么不能直接 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 ✅ 单独失败 ✅

在批量请求场景中:

失败是常态,而不是异常

我们要做的是:

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

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

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

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

八、总结一句话

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

通过:

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

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

相关推荐
Highcharts.js4 小时前
用Highcharts开发动态主从图表|双图联动的时间序列图表示例
javascript·数据库·信息可视化·highcharts·图表开发·动态图表
志尊宝4 小时前
Vue3 零基础每日笔记(076):防抖节流的正确使用——搜索框、按钮防重复提交、滚动监听
javascript·vue.js·笔记
能源革命5 小时前
Vue 网格拖拽布局组件全景指南:7 大方案深度对比
前端·javascript·vue.js
雷工笔记5 小时前
KingFusion 驾驶舱开发:ECharts小时模板实现动态时间窗口
javascript
知野小兔5 小时前
JavaScript中Map和Set详解
javascript
daols885 小时前
vue 表格组件 vxe-table 实现自定义多行编辑功能
前端·javascript·vue.js·vxe-table
志尊宝5 小时前
Vue3 零基础每日笔记(075):图片懒加载与骨架屏
javascript·vue.js·笔记
IT_Octopus6 小时前
【零基础入门 LLM 开发 · Day 11】:ChatOpenAI vs init_chat_model——一行换供应商
java·前端·javascript
柚yuzumi6 小时前
React 19 Hooks 入门:函数组件的四大法宝 (useState / useEffect / useRef / useContext)
前端·javascript·架构