JavaScript如何利用Promise控制并发请求个数


Posted in Javascript onMay 14, 2021

一、场景

假设现在有这么一种场景:现有 30 个异步请求需要发送,但由于某些原因,我们必须将同一时刻并发请求数量控制在 5 个以内,同时还要尽可能快速的拿到响应结果。

如图所示:

JavaScript如何利用Promise控制并发请求个数

上图这样的排队和并发请求的场景基本类似,窗口只有三个,人超过三个之后,后面的人只能排队了。

二、串行和并行

  • 串行:一个异步请求完了之后在进行下一个请求
  • 并行:多个异步请求同时进行

串行举例:

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.3water.com/article/211898.htm

2、https://www.3water.com/article/212277.htm

Javascript 相关文章推荐
innerText和innerHTML 一些问题分析
May 18 Javascript
让你的CSS像Jquery一样做筛选的实现方法
Jul 10 Javascript
深入理解Javascript作用域与变量提升
Dec 09 Javascript
jquery获取颜色在ie和ff下的区别示例介绍
Mar 28 Javascript
JavaScript设计模式之外观模式实例
Oct 10 Javascript
js中window.open的参数及注意注意事项
Jul 06 Javascript
JavaScript仿网易选项卡制作代码
Oct 06 Javascript
详解Vue 全局引入bass.scss 处理方案
Mar 26 Javascript
微信小程序中的店铺评分组件及vue中用svg实现的评分显示组件
Nov 16 Javascript
借助云开发实现小程序短信验证码的发送
Jan 06 Javascript
vue elementui 实现搜索栏公共组件封装的实例代码
Jan 20 Javascript
Vue页面手动刷新,实现导航栏激活项还原到初始状态
Aug 06 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
为php4加入动态flash文件的生成的支持
2006/10/09 PHP
PHP 网页过期时间的控制代码
2009/06/29 PHP
分享PHP header函数使用教程
2013/09/05 PHP
ThinkPHP实现带验证码的文件上传功能实例
2014/11/01 PHP
PHP封装cURL工具类与应用示例
2019/07/01 PHP
JS对img进行操作(换图片/切图/轮换/停止)
2013/04/17 Javascript
window.onresize 多次触发的解决方法
2013/11/08 Javascript
jQuery实现强制cookie过期方法汇总
2015/05/22 Javascript
jquery实现点击向下展开菜单项(伸缩导航)效果
2015/08/22 Javascript
JS添加删除DIV的简单实例
2016/07/08 Javascript
深入理解jQuery3.0的domManip函数
2016/09/01 Javascript
vue 怎么创建组件及组件使用方法
2017/07/27 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
EL表达式截取字符串的函数说明
2017/09/22 Javascript
移动前端图片压缩上传的实例
2017/12/06 Javascript
微信小程序动态设置图片大小的方法
2019/11/21 Javascript
在Vue中使用antv的示例代码
2020/06/29 Javascript
python3.0 字典key排序
2008/12/24 Python
python基础教程之数字处理(math)模块详解
2014/03/25 Python
Python中__name__的使用实例
2015/04/14 Python
Python Pillow Image Invert
2019/01/22 Python
浅谈Python中的可迭代对象、迭代器、For循环工作机制、生成器
2019/03/11 Python
深入了解和应用Python 装饰器 @decorator
2019/04/02 Python
selenium+PhantomJS爬取豆瓣读书
2019/08/26 Python
python psutil监控进程实例
2019/12/17 Python
pytorch中的inference使用实例
2020/02/20 Python
解决python ThreadPoolExecutor 线程池中的异常捕获问题
2020/04/08 Python
TensorFlow的reshape操作 tf.reshape的实现
2020/04/19 Python
Notino意大利:购买香水和化妆品
2018/11/14 全球购物
简单说说tomcat的配置
2013/05/28 面试题
体育教育毕业生自荐信
2014/06/29 职场文书
新农村建设汇报材料
2014/08/15 职场文书
农村文化活动总结
2014/08/28 职场文书
2015年小学语文教师工作总结
2015/10/23 职场文书
python自动计算图像数据集的RGB均值
2021/06/18 Python
一篇文章带你深入了解Mysql触发器
2021/08/02 MySQL