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 按钮点击触发(兼容IE、火狐)
Aug 07 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
Aug 14 Javascript
javascript 判断整数方法分享
Dec 16 Javascript
原生js实现移动端瀑布流式代码示例
Dec 18 Javascript
js实现的页面加载完毕之前loading提示效果完整示例【附demo源码下载】
Aug 02 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
Nov 25 Javascript
JS区分Object与Aarry的六种方法总结
Feb 27 Javascript
vue使用el-upload上传文件及Feign服务间传递文件的方法
Mar 15 Javascript
利用node 判断打开的是文件 还是 文件夹的实例
Jun 10 Javascript
在Vue中使用HOC模式的实现
Aug 23 Javascript
Ant Design的可编辑Tree的实现操作
Oct 31 Javascript
javascript实现搜索筛选功能实例代码
Nov 12 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
国王的咖啡这么大来头,名字的由来是什么
2021/03/03 咖啡文化
PHP 多维数组排序实现代码
2009/08/05 PHP
支持数组的ADDSLASHES的php函数
2010/02/16 PHP
1亿条数据如何分表100张到Mysql数据库中(PHP)
2015/07/29 PHP
zen_cart实现支付前生成订单的方法
2016/05/06 PHP
php DES加密算法实例分析
2019/09/18 PHP
PHP 命名空间和自动加载原理与用法实例分析
2020/04/29 PHP
javascript 写类方式之十
2009/07/05 Javascript
利用jquery的获取JS文件中的字符串内容
2012/02/14 Javascript
jquery实现按Enter键触发事件示例
2013/09/10 Javascript
node.js中的fs.utimes方法使用说明
2014/12/15 Javascript
$.extend 的一个小问题
2015/06/18 Javascript
JavaScript框架是什么?怎样才能叫做框架?
2015/07/01 Javascript
jquery获取table指定行和列的数据方法(当前选中行、列)
2016/11/07 Javascript
微信小程序 toast 详解及实例代码
2016/11/09 Javascript
Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件
2017/06/29 Javascript
微信小程序中post方法与get方法的封装
2017/09/26 Javascript
使用vue-router beforEach实现判断用户登录跳转路由筛选功能
2018/06/25 Javascript
vue登录注册实例详解
2019/09/14 Javascript
京东优选小程序的实现代码示例
2020/02/25 Javascript
[38:32]DOTA2上海特级锦标赛A组资格赛#2 Secret VS EHOME第二局
2016/02/26 DOTA
Python之日期与时间处理模块(date和datetime)
2017/02/16 Python
python字典DICT类型合并详解
2017/08/17 Python
Tensorflow模型实现预测或识别单张图片
2019/07/19 Python
django之静态文件 django 2.0 在网页中显示图片的例子
2019/07/28 Python
python 检查数据中是否有缺失值,删除缺失值的方式
2019/12/02 Python
Python 3.8 新功能大揭秘【新手必学】
2020/02/05 Python
python实现小程序推送页面收录脚本
2020/04/20 Python
Python环境管理virtualenv&amp;virtualenvwrapper的配置详解
2020/07/01 Python
Pandas的数据过滤实现
2021/01/15 Python
html5 touch事件实现触屏页面上下滑动(一)
2016/03/10 HTML / CSS
俄罗斯建筑和装饰材料在线商店:Stroilandia
2020/07/25 全球购物
Java如何获得ResultSet的总行数
2016/09/03 面试题
企业办公室岗位职责
2014/03/12 职场文书
法定代表人身份证明书
2015/06/18 职场文书
创业计划书之DIY自助厨房
2019/09/06 职场文书