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 相关文章推荐
IE6下JS动态设置图片src地址问题
Jan 08 Javascript
一些主流JS框架中DOMReady事件的实现小结
Feb 12 Javascript
关于使用 jBox 对话框的提交不能弹出问题解决方法
Nov 07 Javascript
js格式化金额可选是否带千分位以及保留精度
Jan 28 Javascript
express的中间件cookieParser详解
Dec 04 Javascript
jquery.ajax之beforeSend方法使用介绍
Dec 08 Javascript
利用原生js和jQuery实现单选框的勾选和取消操作的方法
Sep 04 Javascript
简单了解Javscript中兄弟ifream的方法调用
Jun 17 Javascript
js中关于Blob对象的介绍与使用
Nov 29 Javascript
webpack+vue.js构建前端工程化的详细教程
May 10 Javascript
微信小程序自定义顶部组件customHeader的示例代码
Jun 03 Javascript
Axios代理配置及封装响应拦截处理方式
Apr 07 Vue.js
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
php 动态多文件上传
2009/01/18 PHP
PHP使用mysql与mysqli连接Mysql数据库用法示例
2016/07/07 PHP
php实现socket推送技术的示例
2017/12/20 PHP
javascript 用函数语句和表达式定义函数的区别详解
2014/01/06 Javascript
js实现跟随鼠标移动且带关闭功能的图片广告实例
2015/02/26 Javascript
简介JavaScript中toTimeString()方法的使用
2015/06/12 Javascript
Javascript实现图片加载从模糊到清晰显示的方法
2016/06/21 Javascript
jquery日历插件e-calendar升级版
2016/11/10 Javascript
JS正则RegExp.test()使用注意事项(不具有重复性)
2016/12/28 Javascript
简单的JS控制button颜色随点击更改的实现方法
2017/04/17 Javascript
谈谈JS中的!!
2017/12/07 Javascript
webpack4.x下babel的安装、配置及使用详解
2019/03/07 Javascript
Node.js如何优雅的封装一个实用函数的npm包的方法
2019/04/29 Javascript
js如何实现元素曝光上报
2019/08/07 Javascript
简单使用webpack打包文件的实现
2019/10/29 Javascript
JavaScript对象原型链原理解析
2020/01/22 Javascript
three.js利用射线Raycaster进行碰撞检测
2020/03/12 Javascript
[04:26]DOTA2上海特锦赛小组赛第二日 TOP10精彩集锦
2016/02/27 DOTA
python合并文本文件示例
2014/02/07 Python
python通过pil模块将raw图片转换成png图片的方法
2015/03/16 Python
Python数据分析之真实IP请求Pandas详解
2016/11/18 Python
python中字符串数组逆序排列方法总结
2019/06/23 Python
PyCharm无法识别PyQt5的2种解决方法,ModuleNotFoundError: No module named 'pyqt5'
2020/02/17 Python
pycharm的python_stubs问题
2020/04/08 Python
Pycharm plot独立窗口显示的操作
2020/12/11 Python
用gpu训练好的神经网络,用tensorflow-cpu跑出错的原因及解决方案
2021/03/03 Python
莫斯科购买书籍网站:Book24
2020/01/12 全球购物
军校制空专业毕业生自我鉴定
2013/11/16 职场文书
上班打牌检讨书
2014/02/07 职场文书
保护环境倡议书100字
2014/05/19 职场文书
团拜会策划方案
2014/06/07 职场文书
学校食品安全实施方案
2014/06/14 职场文书
临床医学生职业规划书范文
2014/10/25 职场文书
银行给客户的感谢信
2015/01/23 职场文书
分析Python感知线程状态的解决方案之Event与信号量
2021/06/16 Python
关于Nginx中虚拟主机的一些冷门知识小结
2022/03/03 Servers