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函数
Apr 09 Javascript
javascript parseInt与Number函数的区别
Jan 21 Javascript
JS获取整个页面文档的实现代码
Dec 15 Javascript
javascript实现控制div颜色
Jul 07 Javascript
总结几道关于Node.js的面试问题
Jan 11 Javascript
微信小程序如何获取openid及用户信息
Jan 26 Javascript
微信小程序开发的基本流程步骤
Jan 31 Javascript
深入浅出vue图片路径的实现
Sep 04 Javascript
js实现转动骰子模型
Oct 24 Javascript
如何在JavaScript中创建具有多个空格的字符串?
Feb 23 Javascript
利用Vue实现简易播放器的完整代码
Dec 30 Vue.js
jQuery实现全选按钮
Jan 01 jQuery
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
php牛逼的面试题分享
2013/01/18 PHP
PHP执行Curl时报错提示CURL ERROR: Recv failure: Connection reset by peer的解决方法
2014/06/26 PHP
thinkphp缓存技术详解
2014/12/09 PHP
PHP中模拟链表和链表的基本操作示例
2016/02/27 PHP
centos+php+coreseek+sphinx+mysql之一coreseek安装篇
2016/10/25 PHP
thinkphp5.1框架模板布局与模板继承用法分析
2019/07/19 PHP
javascript引用对象的方法代码
2007/08/13 Javascript
Javascript 面向对象编程(coolshell)
2012/03/18 Javascript
jQuery .attr()和.removeAttr()方法操作元素属性示例
2013/07/16 Javascript
jquery遍历之parent()和parents()的区别及parentsUntil()方法详解
2013/12/02 Javascript
javascript 用函数语句和表达式定义函数的区别详解
2014/01/06 Javascript
解决WordPress使用CDN后博文无法评论的错误
2015/12/15 Javascript
JS基础随笔(菜鸟必看篇)
2016/07/13 Javascript
AngularJS 视图详解及示例代码
2016/08/17 Javascript
Bootstrap基本插件学习笔记之Tooltip提示工具(18)
2016/12/08 Javascript
超全面的JavaScript开发规范(推荐)
2017/01/21 Javascript
基于vue实现分页/翻页组件paginator示例
2017/03/09 Javascript
通过fastclick源码分析彻底解决tap“点透”
2017/12/24 Javascript
Vue+SpringBoot开发V部落博客管理平台
2017/12/27 Javascript
vue项目打包之后背景样式丢失的解决方案
2019/01/17 Javascript
[01:11:35]Liquid vs LGD 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python获取中文字符串长度的方法
2018/11/14 Python
python自动化UI工具发送QQ消息的实例
2019/08/27 Python
HTML5打开本地app应用的方法
2016/03/31 HTML / CSS
html5开发之viewport使用
2013/10/17 HTML / CSS
戴森香港官方网站:Dyson香港
2021/02/11 全球购物
信息专业学生学习的自我评价
2014/02/17 职场文书
保密工作整改情况汇报
2014/11/06 职场文书
2014年初中班主任工作总结
2014/11/08 职场文书
介绍信格式
2015/01/30 职场文书
天坛导游词
2015/02/02 职场文书
英语辞职信怎么写
2015/02/28 职场文书
2016年助残日旅游活动总结
2016/04/01 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书
简单聊聊Vue中的计算属性和属性侦听
2021/10/05 Vue.js
mysql 体系结构和存储引擎介绍
2022/05/06 MySQL