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 变量基础知识
Nov 07 Javascript
jquery 跨域访问问题解决方法(笔记)
Jun 08 Javascript
基于IE下ul li 互相嵌套时的bug,排查,解决过程以及心得介绍
May 07 Javascript
jquery.ui.draggable中文文档(原文翻译)
Nov 15 Javascript
关于JavaScript中name的意义冲突示例介绍
May 29 Javascript
node.js+Ajax实现获取HTTP服务器返回数据
Nov 26 Javascript
JS实现移动端判断上拉和下滑功能
Aug 07 Javascript
vue获取元素宽、高、距离左边距离,右,上距离等还有XY坐标轴的方法
Sep 05 Javascript
微信小程序实现带缩略图轮播效果
Nov 04 Javascript
Vue 实现v-for循环的时候更改 class的样式名称
Jul 17 Javascript
Vue项目打包编译优化方案
Sep 16 Javascript
JavaScript编码小技巧分享
Sep 17 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
php下实现一个阿拉伯数字转中文数字的函数
2008/07/10 PHP
php图像验证码生成代码
2017/06/08 PHP
jquery延迟加载外部js实现代码
2013/01/11 Javascript
jquery win 7透明弹出层效果的简单代码
2013/08/06 Javascript
在服务端(Page.Write)调用自定义的JS方法详解
2013/08/09 Javascript
javascript中实现兼容JAVA的hashCode算法代码分享
2020/08/11 Javascript
jQuery中click事件的定义和用法
2014/12/20 Javascript
Webwork 实现文件上传下载代码详解
2016/02/02 Javascript
教你用javascript实现随机标签云效果_附代码
2016/03/16 Javascript
深入浅析Extjs中store分组功能的使用方法
2016/04/20 Javascript
通过sails和阿里大于实现短信验证
2017/01/04 Javascript
JavaScript手风琴页面制作
2017/05/17 Javascript
vue 里面使用axios 和封装的示例代码
2017/09/01 Javascript
js canvas实现简单的图像扩散效果
2020/06/28 Javascript
关于vue-router的beforeEach无限循环的问题解决
2017/09/09 Javascript
Element-ui之ElScrollBar组件滚动条的使用方法
2018/09/14 Javascript
python中管道用法入门实例
2015/06/04 Python
Pythont特殊语法filter,map,reduce,apply使用方法
2016/02/27 Python
Python 登录网站详解及实例
2017/04/11 Python
Python基础教程之利用期物处理并发
2018/03/29 Python
利用Python在一个文件的头部插入数据的实例
2018/05/02 Python
使用Template格式化Python字符串的方法
2019/01/22 Python
解决python中画图时x,y轴名称出现中文乱码的问题
2019/01/29 Python
python实现操作文件(文件夹)
2019/10/31 Python
Python使用QQ邮箱发送邮件报错smtplib.SMTPAuthenticationError
2019/12/20 Python
在tensorflow中设置保存checkpoint的最大数量实例
2020/01/21 Python
python中通过pip安装库文件时出现“EnvironmentError: [WinError 5] 拒绝访问”的问题及解决方案
2020/08/11 Python
H5仿微信界面教程(一)
2017/07/05 HTML / CSS
如何用Java实现列出某个目录下的所有子目录
2015/07/20 面试题
销售文员岗位职责
2013/11/29 职场文书
个人现实表现材料
2014/02/04 职场文书
建议书怎么写
2014/03/12 职场文书
经典安踏广告词
2014/03/21 职场文书
副主任竞聘演讲稿
2014/08/18 职场文书
最美家庭活动方案
2014/08/31 职场文书
Shell脚本一键安装Nginx服务自定义Nginx版本
2022/03/20 Servers