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实现)MapBar中坐标的加密和解密的脚本
May 16 Javascript
Javascript 设计模式(二) 闭包
May 26 Javascript
JS二维数组的定义说明
Mar 03 Javascript
AngularJS + Node.js + MongoDB开发的基于高德地图位置的通讯录
Jan 02 Javascript
javascript中call apply 的应用场景
Apr 16 Javascript
JQuery选择器、过滤器大整理
May 26 Javascript
网页中的图片查看器viewjs使用方法
Jul 11 Javascript
基于Vue单文件组件详解
Sep 15 Javascript
jquery radio 动态控制选中失效问题的解决方法
Feb 28 jQuery
layuiAdmin循环遍历展示商品图片列表的方法
Sep 16 Javascript
基于JavaScript实现大文件上传后端代码实例
Aug 18 Javascript
js+cavans实现图片滑块验证
Sep 29 Javascript
Vue接口封装的完整步骤记录
Vue全家桶入门基础教程
js之ajax文件上传
May 13 #Javascript
react合成事件与原生事件的相关理解
vue实现可拖拽的dialog弹框
vue如何批量引入组件、注册和使用详解
JavaScript继承的三种方法实例
May 12 #Javascript
You might like
memcached 和 mysql 主从环境下php开发代码详解
2010/05/16 PHP
比较简单的百度网盘文件直链PHP代码
2013/03/24 PHP
PHP导出EXCEL快速开发指南--PHPEXCEL的使用详解
2013/06/03 PHP
深入PHP nl2br()格式化输出的详解
2013/06/05 PHP
学习从实践开始之jQuery插件开发 对话框插件开发
2012/04/26 Javascript
基于JQuery的模拟苹果桌面Dock效果(稳定版)
2012/10/15 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
js中this用法实例详解
2015/05/05 Javascript
js获取字符串字节数方法小结
2015/06/09 Javascript
最简单的JavaScript图片轮播代码(两种方法)
2015/12/18 Javascript
BootStrap智能表单实战系列(七)验证的支持
2016/06/13 Javascript
网页瀑布流布局jQuery实现代码
2016/10/21 Javascript
AngularJS入门教程之数据绑定用法示例
2016/11/01 Javascript
jquery uploadify如何取消已上传成功文件
2017/02/08 Javascript
Spring Boot+AngularJS+BootStrap实现进度条示例代码
2017/03/02 Javascript
详解Vue 开发模式下跨域问题
2017/06/06 Javascript
移动端Ionic App 资讯上下循环滚动的实现代码(跑马灯效果)
2017/08/29 Javascript
教你搭建按需加载的Vue组件库(小结)
2019/07/29 Javascript
js脚本中执行java后台代码方法解析
2019/10/11 Javascript
[03:35]2018年度DOTA2最佳辅助位选手5号位-完美盛典
2018/12/17 DOTA
打印出python 当前全局变量和入口参数的所有属性
2009/07/01 Python
Python字符串拼接、截取及替换方法总结分析
2016/04/13 Python
解决python3在anaconda下安装caffe失败的问题
2017/06/15 Python
Python读取Json字典写入Excel表格的方法
2018/01/03 Python
Python干货:分享Python绘制六种可视化图表
2018/08/27 Python
Python 利用scrapy爬虫通过短短50行代码下载整站短视频
2018/10/29 Python
计算机二级python学习教程(2) python语言基本语法元素
2019/05/16 Python
Python日期格式和字符串格式相互转换的方法
2020/02/18 Python
python画图常规设置方式
2020/03/05 Python
Python的PIL库中getpixel方法的使用
2020/04/09 Python
python 实现的车牌识别项目
2021/01/25 Python
网上祭英烈活动总结
2015/02/04 职场文书
大学生敬老院活动总结
2015/05/07 职场文书
护士业务学习心得体会
2016/01/25 职场文书
《打电话》教学反思
2016/02/22 职场文书
小程序与后端Java接口交互实现HelloWorld入门
2021/07/09 Java/Android