JavaScript如何利用Promise控制并发请求个数

 更新时间:2021年05月14日 11:49:43   作者:二九君  
大家都知道js是单线程,并不存在真正的并发,但是由于JavaScript的Event Loop机制,使得异步函数调用有了“并发”这样的假象。这篇文章主要给大家介绍了关于JavaScript如何利用Promise控制并发请求个数的相关资料,需要的朋友可以参考下

一、场景

假设现在有这么一种场景:现有 30 个异步请求需要发送,但由于某些原因,我们必须将同一时刻并发请求数量控制在 5 个以内,同时还要尽可能快速的拿到响应结果。

如图所示:

上图这样的排队和并发请求的场景基本类似,窗口只有三个,人超过三个之后,后面的人只能排队了。

二、串行和并行

  • 串行:一个异步请求完了之后在进行下一个请求
  • 并行:多个异步请求同时进行

串行举例:

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.jb51.net/article/211898.htm

2、https://www.jb51.net/article/212277.htm

相关文章

  • 前端如何用canvas实现图片的等比例缩放

    前端如何用canvas实现图片的等比例缩放

    这篇文章主要介绍了如何使用HTML和JavaScript加载、读取、缩放和绘制图片到canvas上的相关资料,文中通过代码介绍的非常详细,对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-11-11
  • ECMAScript6函数默认参数

    ECMAScript6函数默认参数

    这篇文章主要介绍了ECMAScript6函数默认参数的相关资料,需要的朋友可以参考下
    2015-06-06
  • JS中浮点数精度问题的分析与解决方法

    JS中浮点数精度问题的分析与解决方法

    在js中我们有时会遇到计算,通过加减乘除处理某些业务,那么这时候如果不做任何处理,就会出现如下典型的精度丢失问题,下面这篇文章主要给大家介绍了关于JS中浮点数精度问题的分析与解决方法,需要的朋友可以参考下
    2022-04-04
  • JavaScript详解使用Promise处理回调地狱与async await修饰符

    JavaScript详解使用Promise处理回调地狱与async await修饰符

    这篇文章主要介绍了JavaScript使用Promise处理回调地狱与async await修饰符,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • MQTT.js 入门使用教程

    MQTT.js 入门使用教程

    MQTT.js 是一个开源的 MQTT 协议的客户端库,使用 JavaScript 编写,主要用于 Node.js 和 浏览器环境中,这篇文章主要介绍了MQTT.js 入门教程,需要的朋友可以参考下
    2023-04-04
  • JS库之Waypoints的用法详解

    JS库之Waypoints的用法详解

    waypoints的功能非常强大,一款用于捕获各种滚动事件的插件,下面跟随脚本之家小编一起学习JS库之Waypoints的用法吧
    2017-09-09
  • 微信公众号h5使用微信支付及支付宝支付的步骤(前端)

    微信公众号h5使用微信支付及支付宝支付的步骤(前端)

    微信H5支付是一种支付解决方案,主要适用于商户在微信客户端外的移动端网页上展示商品或服务的场景,这篇文章主要给大家介绍了关于微信公众号h5使用微信支付及支付宝支付(前端)的相关资料,需要的朋友可以参考下
    2024-07-07
  • JavaScript/jQuery实现切换页面效果

    JavaScript/jQuery实现切换页面效果

    这篇文章主要为大家详细介绍了JavaScript或jQuery实现切换页面效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 微信小程序简洁登录页面的实现(附源码)

    微信小程序简洁登录页面的实现(附源码)

    本文主要介绍了微信小程序简洁登录页面的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • js在指定位置增加节点函数insertBefore()用法实例

    js在指定位置增加节点函数insertBefore()用法实例

    这篇文章主要介绍了js在指定位置增加节点函数insertBefore()用法,实例分析了insertBefore()函数追加结点的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01

最新评论