使用场景

在开发中,我们可能会遇到一些对异步请求数做并发量限制的场景,比如说微信小程序的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;}// 发起请求apiasync 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
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. 允许使用者对每个请求设置缓存处理。

优点:

  1. 不修改用户原来的request api代码。对原有代码无副作用。
  2. 不修改request api的调用方式。用户可以无缝的使用被RequestDecorator封装过的request。
  3. 可扩展,后续可能不止支持并发量限制,还可能增加缓存、retry等额外的功能。

结语

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

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

  1. 谷歌为什么把几十亿行代码放在一个库?

    <ACM通信>有一篇论文<为什么 Google 要把几十亿行代码放在一个库?>,作者是谷歌基础设施小组的工程师.作者详细讲述了Google的代码为什么全部放在一个库里面. 一. ...

  2. python爬虫实战:利用scrapy,短短50行代码下载整站短视频

    近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法.这忙我得帮,少不得就抓包分析了一下这个app,找到了视频的下载链接,帮他解决了这个小问题 ...

  3. 如何用50行代码构建情感分类器

    选自Toward Data Science,作者:Rohith Gandhi,机器之心编译. 本文介绍了如何构建情感分类器,从介绍自然语言处理开始,一步一步讲述构建过程. 自然语言处理简介 语言把人类 ...

  4. Google 为什么把几十亿行代码放在一个库

    <ACM通信>有一篇论文<为什么 Google 要把几十亿行代码放在一个库?>,作者是谷歌基础设施小组的工程师.作者详细讲述了Google的代码为什么全部放在一个库里面. 一. ...

  5. pyquery获取不到网页完整源代码_爬虫神器之PyQuery实用教程(二),50行代码爬取穷游网...

    爬虫神器之PyQuery实用教程(二),50行代码爬取穷游网 前言 上篇文章 PyQuery (一) 回顾.今天来介绍具体 PyQuery 的使用方法. 穷游网目标与分析 开始之前,按照之前的套路一步 ...

  6. 【PyTorch】50行代码实现GAN——PyTorch

    本文来源于PyTorch中文网. 一直想了解GAN到底是个什么东西,却一直没能腾出时间来认真研究,前几日正好搜到一篇关于PyTorch实现GAN训练的文章,特将学习记录如下,本文主要包含两个部分:GA ...

  7. python跑酷游戏源码_HTML5游戏实战(1):50行代码实现正面跑酷游戏

    前段时间看到一个"熊来了"的HTML5跑酷游戏,它是一个典型的正面2D跑酷游戏,这里借用它来介绍一下用Gamebuilder+CanTK开发正面跑酷游戏的基本方法. CanTK(C ...

  8. 转:目标50行代码之内完成3d编辑器功能

    1024程序员节刚过,手痒想实现一个html的3d编辑器,看了three.js  同时还看了网上流传已久的<<基于 HTML5 Canvas 的简易 2D 3D 编辑器>>,都 ...

  9. 利用scrapy,短短50行代码下载整站短视频

    一.撕开爬虫的面纱--爬虫是什么,它能做什么 爬虫是什么 爬虫就是一段能够从互联网上高效获取数据的程序. 我们每天都在从互联网上获取数据.当打开浏览器访问百度的时候,我们就从百度的服务器获取数据,当拿 ...

最新文章

  1. vue一二级联动清空二级数据_【周一实用技巧】二级联动还不够,自动更新才最牛。Excel 2013利用数据验证条件制作一级、二级联动和自动更新下拉列表...
  2. 朴素贝叶斯原理及实现
  3. Fedora15安装NVIDIA显卡驱动全过程
  4. 6.824 MapReduce lab1 2020(一)
  5. spring gateway 鉴权_通过spring实现service变成controller,代码得到了简化
  6. 通过修改explorer.exe内存隐藏文件及注册表项
  7. Lua 教程 | 菜鸟教程
  8. Photoshop钢笔工具使用方法
  9. 我的if else代码纯净无暇,一个字也不能简化
  10. ROS之choro功能包
  11. 手把手教你做一个2048 上
  12. 论山寨手机与Android 【6】MTK手机的基带芯片
  13. u盘稳定测试软件,u盘检测工具最新版
  14. golang六个常用的web 框架
  15. 在浏览器中简单输入一个网址,解密其后发生的一切(http请求的详细过程)
  16. appium IOS 报错 [iProxy] recv failed: Operation not permitted
  17. SPECTRUM发布6种新型AWG任意波形发生器
  18. Excel VBA简介
  19. 2022-2028全球房地产众筹平台行业调研及趋势分析报告
  20. Oracle 递归查询SQL

热门文章

  1. Java学习:类的封装、继承和多态
  2. python运维脚本部署jdk_基于Java/Python搭建Web UI自动化环境
  3. 用脚本js把结果转化为固定小数位的形式
  4. BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题
  5. java项目中Classpath路径到底指的是哪里?
  6. 从0开始 Java实习 黑白棋
  7. mysqldatadir 转移
  8. MFC 错误异常,用vs添加资源并为资源定义类后报错:error C2065 : 未声明的标识符...
  9. C++ cin.sync()和cin.ignore()
  10. C++ set的一些用法