如何限制大量请求并发

前言:

1、主流浏览器在 HTTP/1.1 下对同一域名的最大并发请求数通常是 6~8 个。超过限制的请求会进入队列,等待空闲的连接。
2、可以利用Promise模拟任务队列,控制并发请求数量,以避免对服务器造成过大的压力。(先进先出)

代码

一个简单的请求队列调度器,用于控制并发请求的最大数量

import axios from 'axios'export const handQueue = (reqs // 请求总数
) => {reqs = reqs || []const requestQueue = (concurrency) => {concurrency = concurrency || 6 // 最大并发数const queue = [] // 请求池let current = 0const dequeue = () => {while (current < concurrency && queue.length) {current++;const requestPromiseFactory = queue.shift() // 出列requestPromiseFactory().then(() => { // 成功的请求逻辑}).catch(error => { // 失败console.log(error)}).finally(() => {current--dequeue()});}}return (requestPromiseFactory) => {queue.push(requestPromiseFactory) // 入队dequeue()}}const enqueue = requestQueue(6)for (let i = 0; i < reqs.length; i++) {enqueue(() => axios.get('/api/test' + i))}
}

功能拆解

  1. handQueue 函数:
    参数 reqs: 是一个数组,包含需要发送的请求。
    函数的主要目的是对这些请求进行队列管理,确保并发请求的数量不会超过设定的上限。

  2. requestQueue 函数:
    concurrency:最大并发数
    enqueue:用于将新的请求添加到队列并处理它们
    queue: 请求池,用于存储待处理的请求。
    current: 当前正在执行的请求数。

  3. dequeue 函数:

    1、从请求池中取出请求并发送。它在一个循环中运行,直到当前并发请求数current达到最大并发数concurrency或请求池queue为空。
    2、对于每个出队的请求,它首先增加current的值,然后调用请求函数requestPromiseFactory来发送请求。
    3、当请求完成(无论成功还是失败)后,它会减少current的值并再次调用dequeue,以便处理下一个请求。
    
    const dequeue = () => {  while (current < concurrency && queue.length) {  current++;  const requestPromiseFactory = queue.shift() // 出列  requestPromiseFactory()  .then(() => { // 成功的请求逻辑  })  .catch(error => { // 失败  console.log(error)  })  .finally(() => {  current--  dequeue()  });  }  
    }
    
    // 定义返回请求入队函数
    return (requestPromiseFactory) => {  queue.push(requestPromiseFactory) // 入队  dequeue()  
    }
    // 函数返回一个函数,这个函数接受一个参数requestPromiseFactory,表示一个返回Promise的请求工厂函数。
    // 这个返回的函数将请求工厂函数加入请求池queue,并调用dequeue来尝试发送新的请求,
    // 当然也可以自定义axios,利用Promise.all统一处理返回后的结果。
    

    使用一个 while 循环,当当前请求数 current 小于最大并发数 concurrency 并且队列 queue 中有待处理请求时:
    1、从队列中取出第一个请求工厂 requestPromiseFactory。
    2、调用 requestPromiseFactory() 开始请求。
    3、使用 then 和 catch 处理请求成功和失败的逻辑。
    4、在 finally 中,减少当前请求数 current,并递归调用 dequeue,以确保队列持续运行。

  4. 分发逻辑:
    for 循环遍历传入的请求数组 reqs。
    对于每个请求,通过 enqueue 将其加入队列。
    每个请求通过工厂函数 () => axios.get(‘/api/test’ + i) 包装,保证每次调用都返回新的请求 Promise。

优化

  1. 超时管理:
    如果某个请求卡住,会阻塞队列,可为请求设置超时,例如:

    const timeout = (promise, ms) =>Promise.race([promise,new Promise((_, reject) => setTimeout(() => reject('Timeout'), ms)),]);
    
  2. 错误处理:
    重试或告警机制:

     const retry = (fn, retries = 3) =>fn().catch(err => (retries > 0 ? retry(fn, retries - 1) : Promise.reject(err)));
    
  3. 队列清空检测:
    在所有请求处理完成后,触发回调或事件通知:

    if (queue.length === 0 && current === 0) {console.log('All requests completed');
    }
    
  4. 优化后的代码

    import axios from "axios";
    /*** 处理并发请求队列* @param {Array<Function>} reqs 请求总数* @param {Object} options 配置选项* @param {number} options.concurrency 最大并发数* @param {number} options.timeout 请求超时时间 (ms)* @param {Function} options.onQueueEmpty 队列清空后的回调*/
    export const handQueue = (reqs, options = {}) => {const { concurrency = 6, timeout = 10000, onQueueEmpty = () => {} } = options;// 确保请求队列为数组reqs = reqs || [];const queue = [];let current = 0;// 超时管理器const timeoutRequest = (requestPromise, timeout) =>new Promise((resolve, reject) => {const timer = setTimeout(() => reject(new Error("Request timeout")), timeout);requestPromise.then((res) => {clearTimeout(timer);resolve(res);}).catch((err) => {clearTimeout(timer);reject(err);});});// 出列处理const dequeue = async () => {while (current < concurrency && queue.length) {current++;const requestPromiseFactory = queue.shift(); // 出列try {await timeoutRequest(requestPromiseFactory(), timeout); // 包装超时处理console.log("Request success");} catch (error) {console.error("Request failed:", error.message); // 错误处理} finally {current--;dequeue();// 如果队列为空且没有正在处理的请求,调用队列清空回调if (queue.length === 0 && current === 0) {onQueueEmpty();}}}};// 入队函数const enqueue = (requestPromiseFactory) => {queue.push(requestPromiseFactory);dequeue();};// 将请求添加到队列for (let i = 0; i < reqs.length; i++) {enqueue(() => axios.get(`/api/test${i}`));}
    };
    
  5. 使用

    const reqs = Array.from({ length: 20 }, (_, i) => () => axios.get(`/api/test${i}`));
    handQueue(reqs, {concurrency: 4, // 最大并发数timeout: 5000,  // 超时时间 5 秒onQueueEmpty: () => {console.log("All requests have been processed!");},
    });
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode:2274. 不含特殊楼层的最大连续楼层数(排序 Java)

目录 2274. 不含特殊楼层的最大连续楼层数 题目描述&#xff1a; 实现代与解析&#xff1a; 排序 原理思路&#xff1a; 2274. 不含特殊楼层的最大连续楼层数 题目描述&#xff1a; Alice 管理着一家公司&#xff0c;并租用大楼的部分楼层作为办公空间。Alice 决定将一些…

实现AVL树

目录 AVL树概念 AVL树结构 AVL树插入 LL型 - 右单旋 RR型 - 左单旋 LR型 - 左右双旋 RL型 - 右左双旋 插入代码实现 AVL树测试 附AVL树实现完整代码 AVL树概念 前面的博客介绍了搜索二叉树&#xff0c;二叉搜索树-CSDN博客 在某些特定的情况下&#xff0c;⼆叉搜索树…

极客说|微软 Phi 系列小模型和多模态小模型

作者&#xff1a;胡平 - 微软云人工智能高级专家 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&am…

React+redux项目搭建流程

1.创建项目 create-react-app my-project --template typescript // 创建项目并使用typescript2.去除掉没用的文件夹&#xff0c;只保留部分有用的文件 3.项目配置&#xff1a; 配置项目的icon 配置项目的标题 配置项目的别名等&#xff08;craco.config.ts&…

HTML+CSS+JS制作高仿小米官网网站(内附源码,含6个页面)

一、作品介绍 HTMLCSSJS制作一个高仿小米官网网站&#xff0c;包含首页、商品详情页、确认订单页、订单支付页、收货地址管理页、新增收获地址页等6个静态页面。其中每个页面都包含一个导航栏、一个主要区域和一个底部区域。 二、页面结构 1. 顶部导航栏 包含Logo、主导航菜…

obs directx11

创建逻辑 obs 在windows 下分为Opengl 和 directx 两种渲染模式&#xff0c;默认使用的是directx &#xff0c;兼容性更好&#xff1b; 代码路径&#xff1a; E:\opensrc\obs_studio_src\obs-studio\UI\obs-app.cpp 选择渲染模式 const char* OBSApp::GetRenderModule() con…

QT实现 端口扫描暂停和继续功能 3

上篇QT给端口扫描工程增加线程2-CSDN博客 为按钮pushButton_Stop添加clicked事件&#xff0c;功能为暂停扫描&#xff0c;并在暂停后显示继续按钮&#xff0c;点击继续按钮之后继续扫描 1.更新UI 添加继续按钮 点击转到槽则会自动声明 2. 更新 MainWindow.h 需要新增的部分…

微软 2024 最新技术全景洞察

亲爱的小伙伴们&#x1f618;&#xff0c;在求知的漫漫旅途中&#xff0c;若你对深度学习的奥秘、Java 与 Python 的奇妙世界&#xff0c;亦或是读研论文的撰写攻略有所探寻&#x1f9d0;&#xff0c;那不妨给我一个小小的关注吧&#x1f970;。我会精心筹备&#xff0c;在未来…

nginx-限流(请求/并发量)

一. 简述&#xff1a; 在做日常的web运维工作中&#xff0c;难免会遇到服务器流量异常&#xff0c;负载过大等情况。恶意攻击访问/爬虫等非正常性请求&#xff0c;会带来带宽的浪费&#xff0c;服务器压力增大&#xff0c;影响业务质量。 二. 限流方案&#xff1a; 对于这种情…

分布式ID生成-雪花算法实现无状态

雪花算法这里不再赘述&#xff0c;其缺点是有状态&#xff08;多副本隔离时&#xff0c;依赖手动配置workId和datacenterId&#xff09;&#xff0c;代码如下&#xff1a; /*** 雪花算法ID生成器*/ public class SnowflakeIdWorker {/*** 开始时间截 (2017-01-01)*/private st…

(六)vForm 动态表单(数据量大,下拉选卡顿问题)

系列文章目录 (一)vForm 动态表单设计器之使用 (二)vForm 动态表单设计器之下拉、选择 (三)vForm 动态表单解决下拉框无数据显示id问题 (四)vForm 动态表单自定义组件、属性 (五)vForm 动态表单文件上传、下载 文章目录 目录 前言 一、组件改造 1.添加分页所需参…

Edge SCDN高效防护与智能加速

当今数字化时代&#xff0c;网络安全和内容分发效率已成为企业业务发展的关键因素。酷盾安全推出了Edge SCDN解决方案&#xff0c;为企业提供全方位的安全防护和高效的内容分发服务。 一、卓越的安全防护能力 1.DDoS攻击的精准防御&#xff1a;Edge SCDN具备强大的DDoS攻击检测…

【银河麒麟高级服务器操作系统】服务器异常重启故障分析及处理建议

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://document.kylinos.cn 服务器环境以及配置 系统环境 物理机/虚拟机/云…

Go语言中的 os.Stat() 与 os.Lstat() 实际应用中,你该如何选择?

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…

少儿编程:开启多元成长,引领未来之路

今天&#xff0c;想跟大家深入聊聊一个当下热度颇高&#xff0c;却又让不少家长心存疑惑的话题 —— 少儿为什么要学习编程。 咱们先把目光投向国家层面的教育政策风向。近几年&#xff0c;国家对科技创新人才的培养予以了前所未有的重视&#xff0c;一系列重磅政策相继出台&a…

在vscode上

第一步 安装插件 &#xff08;1&#xff09;从菜单处打开vscode&#xff0c;之后点击左侧“拓展”&#xff0c;在搜索栏输入“platform”&#xff0c;安装这个插件。 注&#xff1a;安装过程可能会慢一点&#xff0c;可以尝试连接自己的热点 &#xff08;2&#xff09;安装完…

产品心、用户脑、押重注......解读vivo穿越周期之道

出品 | 何玺 排版 | 叶媛 国内科技企业中&#xff0c;vivo绝对算个“异类”。给人以平和谦逊、稳健踏实的印象&#xff0c;却极具实力&#xff01; 回望vivo发展历程&#xff0c;这家拥有近30年历史的超大型全球化产业科技生态型公司&#xff0c;从功能机到智能机一路走来&am…

jenkins入门4 --window执行execute shell

1、启动关闭jenkins 在Windows环境下&#xff0c;如果你需要关闭Jenkins服务&#xff0c;可以通过以下几种方式&#xff1a; 1、使用Windows服务管理器&#xff1a; 打开“运行”对话框&#xff08;Win R&#xff09;&#xff0c;输入services.msc&#xff0c;然后回车。 在服…

矩阵碰一碰发视频源码搭建全解析,支持OEM

在数字化营销与互动体验需求日益增长的当下&#xff0c;矩阵碰一碰发视频功能以其独特的交互性和高效的信息传播能力&#xff0c;正逐渐成为吸引用户、提升品牌影响力的有力工具。本文将深入探讨如何搭建矩阵碰一碰发视频的源码&#xff0c;帮助开发者实现这一创新功能。 一、技…

软件确认测试和验收测试有什么区别?

在当今快速发展的软件行业中&#xff0c;软件确认测试与验收测试是软件产品生产周期中的重要步骤&#xff0c;但很多人容易混淆&#xff0c;那么这两者之间究竟有什么区别呢? 软件确认测试是一个旨在确保软件产品符合用户需求规格的过程。它对软件的功能、性能和可用性进行深…