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中点击空白区域时文本框与隐藏层的显示与影藏问题
Aug 26 Javascript
jQuery切换所有复选框选中状态的方法
Jul 02 Javascript
js表单提交和submit提交的区别实例分析
Dec 10 Javascript
MUI实现上拉加载和下拉刷新效果
Jun 30 Javascript
bootstrap fileinput实现文件上传功能
Aug 23 Javascript
vue-music关于Player播放器组件详解
Nov 28 Javascript
vue组件中使用iframe元素的示例代码
Dec 13 Javascript
详解vue后台系统登录态管理
Apr 02 Javascript
JavaScript鼠标拖拽事件详解
Apr 03 Javascript
js实现简单五子棋游戏
May 28 Javascript
解决vue一个页面中复用同一个echarts组件的问题
Jul 19 Javascript
JavaScript实现拖拽和缩放效果
Aug 24 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
PHP脚本的10个技巧(8)
2006/10/09 PHP
PHP简单实现文本计数器的方法
2016/04/28 PHP
php实现批量删除挂马文件及批量替换页面内容完整实例
2016/07/08 PHP
手把手编写PHP框架 深入了解MVC运行流程
2016/09/19 PHP
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
Jquery升级新版本后选择器的语法问题
2010/06/02 Javascript
jQuery 实现侧边浮动导航菜单效果
2014/12/26 Javascript
JS获取随机数和时间转换的简单实例
2016/07/10 Javascript
jQuery+CSS3实现仿花瓣网固定顶部位置带悬浮效果的导航菜单
2016/09/21 Javascript
jQuery如何解决IE输入框不能输入的问题
2016/10/08 Javascript
老生常谈javascript的面向对象思想
2017/08/22 Javascript
详解Vue 全局引入bass.scss 处理方案
2018/03/26 Javascript
Angular2之二级路由详解
2018/08/31 Javascript
scrapyd schedule.json setting 传入多个值问题
2019/08/07 Javascript
详解webpack打包vue项目之后生成的dist文件该怎么启动运行
2019/09/06 Javascript
vue 使用 sortable 实现 el-table 拖拽排序功能
2020/12/26 Vue.js
javascript实现倒计时关闭广告
2021/02/09 Javascript
[42:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS OpTic
2018/03/31 DOTA
Python写的英文字符大小写转换代码示例
2015/03/06 Python
python绘图方法实例入门
2015/05/19 Python
在Django的视图(View)外使用Session的方法
2015/07/23 Python
Python实现字典去除重复的方法示例
2017/07/31 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
将Python字符串生成PDF的实例代码详解
2019/05/17 Python
python使用paramiko模块通过ssh2协议对交换机进行配置的方法
2019/07/25 Python
Python如何使用Gitlab API实现批量的合并分支
2019/11/27 Python
python 实现批量替换文本中的某部分内容
2019/12/13 Python
Pytorch框架实现mnist手写库识别(与tensorflow对比)
2020/07/20 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
Python通过len函数返回对象长度
2020/10/22 Python
幼儿园小班评语
2014/04/18 职场文书
单位法人授权委托书范本
2014/10/09 职场文书
2015年主婚人婚礼致辞
2015/07/28 职场文书
导游带团欢迎词
2015/09/30 职场文书
2016国培研修心得体会
2016/01/08 职场文书
Apache Pulsar集群搭建部署详细过程
2022/02/12 Servers