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 相关文章推荐
Js event事件在IE、FF兼容性问题
Jan 01 Javascript
让图片旋转任意角度及JQuery插件使用介绍
Mar 20 Javascript
js中typeof的用法汇总
Dec 12 Javascript
jquery动态更换设置背景图的方法
Mar 25 Javascript
JavaScript函数参数使用带参数名的方式赋值传入的方法
Mar 19 Javascript
JavaScipt中栈的实现方法
Feb 17 Javascript
详解JavaScript数组和字符串中去除重复值的方法
Mar 07 Javascript
js中常用的Tab切换效果(推荐)
Aug 30 Javascript
js实现点击每个li节点,都弹出其文本值及修改
Dec 15 Javascript
Vue中组件之间数据的传递的示例代码
Sep 08 Javascript
jQuery序列化form表单数据为JSON对象的实现方法
Sep 20 jQuery
AI小程序之语音听写来了,十分钟掌握百度大脑语音听写全攻略
Mar 13 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
php中strtotime函数性能分析
2016/11/20 PHP
PHP使用mongoclient简单操作mongodb数据库示例
2019/02/08 PHP
javascript arguments 传递给函数的隐含参数
2009/08/21 Javascript
javascript prototype原型操作笔记
2009/12/07 Javascript
JS复制内容到剪切板的实例代码(兼容IE与火狐)
2013/11/19 Javascript
引用 js在IE与FF之间的区别详细解析
2013/11/20 Javascript
jquery淡化版banner异步图片文字效果切换图片特效
2014/04/08 Javascript
瀑布流布局代码一例
2014/04/11 Javascript
js获取checkbox复选框选中的选项实例
2014/08/24 Javascript
jquery禁止回车触发表单提交
2014/12/12 Javascript
jQuery插件animateSlide制作多点滑动幻灯片
2015/06/11 Javascript
在AngularJS中使用AJAX的方法
2015/06/17 Javascript
JS+DIV+CSS实现仿表单下拉列表效果
2015/08/18 Javascript
jquery结婚电子请柬特效源码分享
2015/08/21 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
2015/10/28 Javascript
Javascript 实现全屏滚动实例代码
2016/12/31 Javascript
微信小程序 PHP后端form表单提交实例详解
2017/01/12 Javascript
原生js实现选项卡功能
2017/03/08 Javascript
详解基于Angular4+ server render(服务端渲染)开发教程
2017/08/28 Javascript
微信小程序中post方法与get方法的封装
2017/09/26 Javascript
JavaScript实现计算圆周率到小数点后100位的方法示例
2018/05/08 Javascript
微信小程序+腾讯地图开发实现路径规划绘制
2019/05/22 Javascript
了解javascript中let和var及const关键字的区别
2019/05/24 Javascript
ES6使用 Array.includes 处理多重条件用法实例分析
2020/03/02 Javascript
Vue仿Bibibili首页的问题
2021/01/21 Vue.js
Pythony运维入门之Socket网络编程详解
2019/04/15 Python
基于TensorFlow常量、序列以及随机值生成实例
2020/01/04 Python
HTML5 drag和drop具体使用详解
2021/01/18 HTML / CSS
斯洛伐克时尚服装网上商店:Cellbes
2016/10/20 全球购物
类的核心特性有哪些
2014/01/01 面试题
幼儿园教师个人反思
2014/01/30 职场文书
单位法人授权委托书范本
2014/10/09 职场文书
升学宴学生致辞
2015/07/27 职场文书
优秀大学生申请书
2019/06/24 职场文书
Python数据分析入门之教你怎么搭建环境
2021/05/13 Python
python绘制简单直方图(质量分布图)的方法
2022/04/21 Python