使用场景

在开发中,我们可能会遇到一些对异步请求数做并发量限制的场景,比如说微信小程序的request并发最多为5个,又或者我们需要做一些批量处理的工作,可是我们又不想同时对服务器发出太多请求(可能会对服务器造成比较大的压力)。这个时候我们就可以对请求并发数进行限制,并且使用排队机制让请求有序的发送出去。

介绍

那么,接下来我们就来讲一下如何实现一个通用的能对请求并发数进行限制的RequestDecorator。我们先来介绍一下它的功能:

  1. 既然涉及到并发数限制,它就肯定允许用户传入最大并发数限制参数:maxLimit
  2. 既然是一个通用的RequestDecorator,那么它应该允许使用者传入其喜欢的异步api(比如ajax, fetch, axios等)。
  3. 为了方便起见,也为了开发便利性,被RequestDecorator封装后的request请求结果都返回一个promise。
  4. 由于使用者传入的异步api不一定是promise类型的,也可能是callback类型的,因此我们提供用户一个needChange2Promise参数,使用者若传入的是callback类型的api,它可以通过将这个参数设置为true来将callback类型转化为promise类型。

分析完功能后,接下来我们就来实现这个东西:

实现

具体代码如下,每一步我基本都做了注释,相信大家能看懂。

const pify = require('pify');

class RequestDecorator {
constructor ({
maxLimit = 5,
requestApi,
needChange2Promise,
}) {
// 最大并发量
this.maxLimit = maxLimit;
// 请求队列,若当前请求并发量已经超过maxLimit,则将该请求加入到请求队列中
this.requestQueue = [];
// 当前并发量数目
this.currentConcurrent = 0;
// 使用者定义的请求api,若用户传入needChange2Promise为true,则将用户的callback类api使用pify这个库将其转化为promise类的。
this.requestApi = needChange2Promise ? pify(requestApi) : requestApi;
}
// 发起请求api
async request(...args) {
// 若当前请求数并发量超过最大并发量限制,则将其阻断在这里。
// startBlocking会返回一个promise,并将该promise的resolve函数放在this.requestQueue队列里。这样的话,除非这个promise被resolve,否则不会继续向下执行。
// 当之前发出的请求结果回来/请求失败的时候,则将当前并发量-1,并且调用this.next函数执行队列中的请求
// 当调用next函数的时候,会从this.requestQueue队列里取出队首的resolve函数并且执行。这样,对应的请求则可以继续向下执行。
if (this.currentConcurrent >= this.maxLimit) {
await this.startBlocking();
}
try {
this.currentConcurrent++;
const result = await this.requestApi(...args);
return Promise.resolve(result);
} catch (err) {
return Promise.reject(err);
} finally {
console.log('当前并发数:', this.currentConcurrent);
this.currentConcurrent--;
this.next();
}
}
// 新建一个promise,并且将该reolsve函数放入到requestQueue队列里。
// 当调用next函数的时候,会从队列里取出一个resolve函数并执行。
startBlocking() {
let _resolve;
let promise2 = new Promise((resolve, reject) => _resolve = resolve);
this.requestQueue.push(_resolve);
return promise2;
}
// 从请求队列里取出队首的resolve并执行。
next() {
if (this.requestQueue.length <= 0) return;
const _resolve = this.requestQueue.shift();
_resolve();
}
} module.exports = RequestDecorator;

样例代码如下:

const RequestDecorator = require('../src/index.js')

// 一个callback类型的请求api
async function delay(num, time, cb) {
setTimeout(() => {
cb(null, num);
}, time);
} // 通过maxLimit设置并发量限制,needChange2Promise将callback类型的请求api转化为promise类型的。
const requestInstance = new RequestDecorator({
maxLimit: 5,
requestApi: delay,
needChange2Promise: true,
}); let promises = [];
for (let i = 0; i < 30; i++) {
// 接下来你就可以像原来使用你的api那样使用它,参数和原来的是一样的
promises.push(requestInstance.request(i, Math.random() * 3000).then(result => console.log('result', result), error => console.log(error)));
}
async function test() {
await Promise.all(promises);
} test();

这样,一个能对请求并发数做限制的通用RequestDecorator就已经实现了。当然,这里还有很多可以继续增加的功能点,比如

  1. 允许使用者设置每个请求的retry次数。
  2. 允许使用者对每个请求设置缓存处理。

结语

以上,就是本篇的全部内容。github仓库地址点击这里。欢迎大家点赞或者star下。如果大家有兴趣的话,也可以一起来完善这个东西。这个项目还不成熟,可能还会有bug,欢迎大家在github上提issue帮助我完善它。如果觉得有帮助的话,麻烦点个赞哦,谢谢。

转:https://www.cnblogs.com/chenjg/p/9638613.html

对请求并发数做限制的通用RequestDecorator的更多相关文章

  1. 不到50行代码实现一个能对请求并发数做限制的通用RequestDecorator

    使用场景 在开发中,我们可能会遇到一些对异步请求数做并发量限制的场景,比如说微信小程序的request并发最多为5个,又或者我们需要做一些批量处理的工作,可是我们又不想同时对服务器发出太多请求(可能会 ...

  2. Node爬虫之——使用async.mapLimit控制请求并发

    一般我们在写爬虫的时候,很多网站会因为你并发请求数太多当做是在恶意请求,封掉你的IP,为了防止这种情况的发生,我们一般会在代码里控制并发请求数,Node里面一般借助async模块来实现. 1. asy ...

  3. 吞吐量(Throughput)、QPS、并发数、响应时间(RT)对系统性能的影响

    首先对吞吐量().QPS.并发数.响应时间(RT)几个概念一直比较模糊,也不知道哪些指标可以较好的衡量系统的性能.今天特意查了些资料做一些记录:首先看一些概念(来自百度百科) 1. 响应时间(RT) ...

  4. 吞吐量(TPS)、QPS、并发数、响应时间(RT)概念

    开发的原因,需要对吞吐量(TPS).QPS.并发数.响应时间(RT)几个概念做下了解,查自百度百科,记录如下:1. 响应时间(RT)  响应时间是指系统对请求作出响应的时间.直观上看,这个指标与人对软 ...

  5. [笔记]吞吐量(TPS)、QPS、并发数、响应时间(RT)概念

    开发的原因,需要对吞吐量(TPS).QPS.并发数.响应时间(RT)几个概念做下了解,查自百度百科,记录如下: 1. 响应时间(RT) 响应时间是指系统对请求作出响应的时间.直观上看,这个指标与人对软 ...

  6. paip.提升性能---- 网站并发数的总结.txt

    paip.提升性能---- 网站并发数的总结.txt 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.n ...

  7. 【转载】nginx 并发数问题思考:worker_connections,worker_processes与 max clients

    注:这个文章主要是作者一直在研究nginx作为http server和反向代理服务器时候所谓最大的max_clients和 worker_connections的计算公式, 其实最后的结论也没有卡上公 ...

  8. windows下修改apache并发数

    还没有尝试 修改apache的最大连接数,方法如下: 步骤一 先修改 /path/apache/conf/httpd.conf文件. # vi httpd.conf 将“#Include conf/e ...

  9. tomcat 最大并发数

    只针对BIO模式,目标请求会sleep两秒再返回结果,通过jmeter测试工具进行并发测试 操作系统:windows && linux tomcat7测试: <Connector ...

随机推荐

  1. Java Map 键值对排序 按key排序和按Value排序

    一.理论准备 Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等. TreeMap:基于红黑树(Red-Black tre ...

  2. Ext.util.Format.date与Ext.Date.format区别, 转换时间戳

    在Extjs中装时间戳使用如下两种都可以: Ext.util.Format.date(time,'U'); Ext.Date.format(time, 'U'); 为了找到它们的区别,查看源代码,以E ...

  3. Laravel Cache 的缓存文件在到期后是否会自动删除

    验证缓存文件是否会自动删除的目的是,防止产生大量的缓存文件,占满磁盘.因为,我最近越来越多的使用 cache 来缓存各类 token. 使用的是 file 作为 CACHE_DRIVER CACHE_ ...

  4. python 全栈开发,Day140(RabbitMQ,基于scrapy-redis实现分布式爬虫)

    一.RabbitMQ 队列 在生产者消费模型中,比如去餐馆吃饭的例子.生产者相当于厨师,队列相当于服务员,消费者就是你. 我们必须通过服务员,才能吃饭! 如果队列满了,队列会一直hold住.必须让消费 ...

  5. python 全栈开发,Day134(爬虫系列之第1章-requests模块)

    一.爬虫系列之第1章-requests模块 爬虫简介 概述 近年来,随着网络应用的逐渐扩展和深入,如何高效的获取网上数据成为了无数公司和个人的追求,在大数据时代,谁掌握了更多的数据,谁就可以获得更高的 ...

  6. websocket+Django+python+paramiko实现web页面执行命令并实时输出

    一.概述 WebSocket WebSocket的工作流程:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过 T ...

  7. javax.inject包

    javax.inject包 java提出的依赖注入标准,有别于以下传统的对象获取方式 构造方法 工厂模式 服务器定位模式(e.g. JNDI) 开发过程中是会有很多层层依赖的对象的,例如,Stopwa ...

  8. Codeforces 449C Jzzhu and Apples 贪心 (看题解)

    Jzzhu and Apples 从大的质因子开始贪心, 如果有偶数个则直接组合, 如果是奇数个留下那个质数的两倍, 其余两两组合. #include<bits/stdc++.h> #de ...

  9. Docker 记一次容器内部修改宿主机挂载目录用户权限后宿主机目录变化

    一.需求: 因公司需求,需制作mysql5.7.22 docker基础镜像,每个项目以此镜像启动一个数据库容器,并且每个项目挂载一个宿主机目录到镜像中数据存储下面用于数据持久化保存以便后期迁移至阿里云 ...

  10. BZOJ2303 [Apio2011]方格染色 并查集

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2303 题意概括 现在有一个N*M矩阵,矩阵上只能填数字0或1 现在矩阵里已经有一些格子被填写了数字 ...