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 相关文章推荐
javascript function、指针及内置对象
Feb 19 Javascript
javascript qq右下角滑出窗口 sheyMsg
Mar 21 Javascript
jqPlot 图表中文API使用文档及源码和在线示例
Feb 07 Javascript
jquery使用jxl插件导出excel示例
Apr 14 Javascript
js实现图片在未加载完成前显示加载中字样
Sep 03 Javascript
JSON 必知必会 观后记
Oct 27 Javascript
解决AngualrJS页面刷新导致异常显示问题
Apr 20 Javascript
zTree获取当前节点的下一级子节点数实例
Sep 05 Javascript
微信小程序实现打开内置地图功能【附源码下载】
Dec 07 Javascript
深入理解Vue Computed计算属性原理
May 29 Javascript
微信小程序 Animation实现图片旋转动画示例
Aug 22 Javascript
JS highcharts动态柱状图原理及实现
Oct 16 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
php获取字符串中各个字符出现次数的方法
2015/02/23 PHP
JavaScript与Image加载事件(onload)、加载状态(complete)
2011/02/14 Javascript
js读写json文件实例代码
2014/10/21 Javascript
如何在node的express中使用socket.io
2014/12/15 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
2015/10/28 Javascript
完美的js div拖拽实例代码
2016/09/24 Javascript
JavaScript 中对象的深拷贝
2016/12/04 Javascript
nodejs搭建本地服务器并访问文件的方法
2017/03/03 NodeJs
JS使用cookie实现只出现一次的广告代码效果
2017/04/22 Javascript
JS实现json对象数组按对象属性排序操作示例
2018/05/18 Javascript
在Vue-cli里应用Vuex的state和mutations方法
2018/09/16 Javascript
非常漂亮的js烟花效果
2020/03/10 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
2020/05/06 Javascript
JavaScript代码模拟鼠标自动点击事件示例
2020/08/07 Javascript
Vue使用screenfull实现全屏效果
2020/09/17 Javascript
解决vue中使用less/sass及使用中遇到无效的问题
2020/10/24 Javascript
Python中用startswith()函数判断字符串开头的教程
2015/04/07 Python
Python实现从URL地址提取文件名的方法
2015/05/15 Python
对python 中re.sub,replace(),strip()的区别详解
2019/07/22 Python
使用Python paramiko模块利用多线程实现ssh并发执行操作
2019/12/05 Python
如何使用python传入不确定个数参数
2020/02/18 Python
浅谈PyTorch中in-place operation的含义
2020/06/27 Python
Python在字符串中处理html和xml的方法
2020/07/31 Python
PyCharm 解决找不到新打开项目的窗口问题
2021/01/15 Python
纯CSS3制作的鼠标悬停时边框旋转
2017/01/03 HTML / CSS
.net面试题
2016/09/17 面试题
大专毕业生自我鉴定
2013/11/21 职场文书
即兴演讲稿
2014/01/04 职场文书
模范家庭事迹材料
2014/02/10 职场文书
帮一个朋友写的求职信
2014/08/09 职场文书
2014年银行个人工作总结
2014/12/05 职场文书
骨干教师考核评语
2014/12/31 职场文书
负责培养人意见
2015/06/05 职场文书
春季运动会加油词
2015/07/18 职场文书
如何用python清洗文件中的数据
2021/06/18 Python
springboot读取resources下文件的方式详解
2022/06/21 Java/Android