Heading for the future

使用 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.jianshu.com/p/cc706239c7ef

posted @ 2020-09-11 08:56  一只菜鸟攻城狮啊  阅读(3413)  评论(2编辑  收藏  举报