使用 Promise 实现任务队列发送请求,实现最大请求数目限制
核心
- 设置最大请求数量,当前请求数量,待执行队列
- 调用时,创建一个新任务,然后判断是否达到最大请求数量,若达到则将任务追加到待执行队列,否则,则直接执行该任务。并返回Promise
- 创建任务时,需要返回一个函数,当该任务开始执行则当前数量加一。当任务执行完毕时使用finally,当前数量减一,并从待执行队列中取出新任务执行
实现
class limitPromise{ constructor(max){ this.max = max; this._count = 0; this._pendingTaskQueue = []; } /** * 调用器,将异步任务函数和它的参数传入 * @param caller 异步任务函数,返回Promise的函数 * @param args 异步任务函数的参数列表 * @returns {Promise<unknown>} 返回一个新的Promise */ call = (caller, ...arg) => { return new Promise((resolve, reject) => { let task = this._createTask(caller, arg, resolve, reject); if(this._count >= this.max) { this._pendingTaskQueue.push(); }else{ task(); } }); } /** * 创建一个任务 * @param caller 实际执行的函数 * @param args 执行函数的参数 * @param resolve * @param reject * @returns {Function} 返回一个任务函数 * @private */ _createTask = (caller, arg, resolve, reject)=> { return () => { // 当前请求数量加一 this._count++; // 实际上是在这里调用了异步任务,并将异步任务的返回(resolve和reject)抛给了上层 caller(...arg) .then(resolve) .catch(reject) .finally(() => { // 任务队列的消费区,利用Promise的finally方法,在异步任务结束后,取出下一个任务执行 this._count--; if(this._pendingTaskQueue.length){ let task = this._pendingTaskQueue.shift(); task(); } }) } } }
使用
假设我们有一个网络请求模块,叫request.js,包含get和post方法,一般情况下,是这样使用的
const request = require('./request') request.get('https://www.baidu.com') .then((res) => { // 处理返回结果 }) .catch(err => { // 处理异常情况 })
现在我们要把它改造成受限制的网络请求,假设请求上限设为10个,并起名叫limitRequest.js。实现如下:
const LimitPromise = require('limit-promise') const request = require('./request') // 请求上限 const MAX = 10 // 核心控制器 const limitP = new LimitPromise(MAX) // 利用核心控制器包装request中的函数 function get (url, params) { return limitP.call(request.get, url, params) } function post (url, params) { return limitP.call(request.post, url, params) } // 导出 module.exports = {get, post}
这里就完成受限请求模块的构建了,是不是很简单,而且调用接口完全没变,只需要引入limitRequest.js替代原先的即可。
参考自
语雀链接🔗 https://www.yuque.com/suihangadam
归来卧占楼千尺,梦落沧波明月舟。