JavaScript 使用 Promise 限制并发请求数量的实现方案

作者:异步漫步

时间:2026-10-24

浏览:612

本文介绍如何在 JavaScript 中使用 Promise 限制同时发起的异步请求数量。通过解析串行与并行的区别,重点讲解利用递归调用和索引追踪实现并发限制的方法。代码示例展示了如何创建请求窗口,确保在控制并发量的同时保持结果顺序,防止内存溢出。

文章目录

一、场景

假设存在一种业务需求:需要发送 30 个异步请求,但受限于服务器或网络条件,必须将同一时刻并发的请求数量限制在 5 个以内,同时要求尽可能快速地获取所有响应结果。

如图所示:

一、场景

该场景类似于排队机制:窗口数量有限(如三个),当人数超过窗口数量时,剩余人员必须排队等待。

二、串行和并行

  • 串行:指一个异步请求执行完毕后,才开始执行下一个请求。
  • 并行:指多个异步请求同时发起并执行。

串行举例:


var p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("1000");
      resolve();
    }, 1000);
  });
};
var p1 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("2000");
      resolve();
    }, 2000);
  });
};
var p2 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("3000");
      resolve();
    }, 3000);
  });
};

p()
  .then(() => {
    return p1();
  })
  .then(() => {
    return p2();
  })
  .then(() => {
    console.log("end");
  });

如示例代码所示,串行模式会从上到下依次执行对应的接口请求,前一个完成后再发起下一个。

并行举例:

通常,当我们需要在多个异步处理完成后执行后续逻辑时,会用到:


Promise.all((promises: [])).then((fun: function));

Promise.all 可以确保 promises 数组中所有 promise 对象都达到 resolve 状态后,才执行 then 回调。


var promises = function () {
  return [1000, 2000, 3000].map((current) => {
    return new Promise(function (resolve, reject) {
      setTimeout(() => {
        console.log(current);
      }, current);
    });
  });
};

Promise.all(promises()).then(() => {
  console.log("end");
});

这时候考虑一个场景:

如果你的 promises 数组中每个对象都是 http 请求,且这样的对象有几十万个。那么会出现的情况是,你在瞬间发出几十万个 http 请求,这样很有可能导致堆积了无数调用栈导致内存溢出。这时候,我们就需要考虑对 Promise.all 做并发限制。Promise.all 并发限制指的是,每个时刻并发执行的 promise 数量是固定的,最终的执行结果还是保持与原来的 Promise.all 一致。

三、代码实现

整体采用递归调用来实现:最初发送的请求数量上限为允许的最大值,并且这些请求中的每一个都应该在完成时继续递归发送,通过传入的索引来确定了 urls 里面具体是那个 URL,保证最后输出的顺序不会乱,而是依次输出。

代码:


function multiRequest(urls, maxNum) {
 const len = urls.length; // 请求总数量
 const res = new Array(len).fill(0); // 请求结果数组
 let sendCount = 0; // 已发送的请求数量
 let finishCount = 0; // 已完成的请求数量
 return new Promise((resolve, reject) => {
     // 首先发送 maxNum 个请求,注意:请求数可能小于 maxNum,所以也要满足条件2
     // 同步的 创建maxNum个next并行请求 然后才去执行异步的fetch 所以一上来就有5个next并行执行
     while (sendCount < maxNum && sendCount < len) { 
         next();
     }
     function next () {
         let current = sendCount ++; // 当前发送的请求数量,后加一 保存当前请求url的位置
         // 递归出口
         if (finishCount >= len) { 
         // 如果所有请求完成,则解决掉 Promise,终止递归
             resolve(res);
             return;
         }
         const url = urls[current];
         fetch(url).then(result => {
             finishCount ++;
             res[current] = result;
             if (current < len) { // 如果请求没有发送完,继续发送请求
                 next();
             }
         }, err => {
             finishCount ++;
             res[current] = err;
             if (current < len) { // 如果请求没有发送完,继续发送请求
                 next();
             }
         });
     }
 });
}

总结:

代码在 while 循环处创建了 maxNum 个"请求窗口"来进行请求,从而达到并行效果,然后 next 函数中进行异步请求,然后通过在.then 里面进行递归进行新请求的调用,实现"一个窗口只进行一个请求,当这个请求执行完成后才进行下一个请求"(每个窗口串行执行,maxNum 个窗口并行执行)。

到此这篇关于 JavaScript 如何利用 Promise 控制并发请求个数的文章就介绍到这了,更多相关 js 用 Promise 控制并发请求内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

参考链接

1、https://www.jb51.net/article/211898.htm

2、https://www.jb51.net/article/212277.htm

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章