Vue并发队列-最大并发数量限制

需求:

  • 设置最大请求数量,当前请求数量,待执行队列
  • 调用时,创建一个新任务,然后判断是否达到最大请求数量,若达到则将任务追加到待执行队列,否则,则直接执行该任务。并返回Promise
  • 创建任务时,需要返回一个函数,当该任务开始执行则当前数量加一。当任务执行完毕时使用finally,当前数量减一,并从待执行队列中取出新任务执行

实现:

JS版本
/* eslint-disable */
export class LimitPromise {
  constructor (max) {
    // 异步任务“并发”上限
    this._max = max
    // 当前正在执行的任务数量
    this._count = 0
    // 等待执行的任务队列
    this._taskQueue = []
  }

  /**
     * 调用器,将异步任务函数和它的参数传入
     * @param caller 异步任务函数,它必须是async函数或者返回Promise的函数
     * @param args 异步任务函数的参数列表
     * @returns {Promise<unknown>} 返回一个新的Promise
     */
  call (caller, ...args) {
    return new Promise((resolve, reject) => {
      const task = this._createTask(caller, args, resolve, reject)
      if (this._count >= this._max) {
        // console.log('count >= max, push a task to queue')
        this._taskQueue.push(task)
      } else {
        task()
      }
    })
  }

  /**
     * 创建一个任务
     * @param caller 实际执行的函数
     * @param args 执行函数的参数
     * @param resolve
     * @param reject
     * @returns {Function} 返回一个任务函数
     * @private
     */
  _createTask (caller, args, resolve, reject) {
    return () => {
      // 实际上是在这里调用了异步任务,并将异步任务的返回(resolve和reject)抛给了上层
      caller(...args)
        .then(resolve)
        .catch(reject)
        .finally(() => {
          // 任务队列的消费区,利用Promise的finally方法,在异步任务结束后,取出下一个任务执行
          this._count--
          if (this._taskQueue.length) {
            // console.log('a task run over, pop a task to run')
            let task = this._taskQueue.shift()
            task()
          } else {
            // console.log('task count = ', count)
          }
        })
      this._count++
      // console.log('task run , task count = ', count)
    }
  }
}

TS版本:
export class LimitPromise {
  _max: number // 异步任务“并发”上限
  _queueList: any[] // 等待执行的任务队列
  _count: number // 当前正在执行的任务数量
  constructor(maxLimit) {
    this._max = maxLimit
    this._queueList = []
    this._count = 0
  }
  /**
   * 调用器,将异步任务函数和它的参数传入
   * @param caller 异步任务函数,它必须是async函数或者返回Promise的函数
   * @param args 异步任务函数的参数列表
   * @returns {Promise<unknown>} 返回一个新的Promise
   */
  call(caller, ...args) {
    return new Promise((resolve, reject) => {
      // 创建一个任务
      const task = () => {
        caller(...args)
          .then((res) => resolve(res))
          .catch((err) => reject(err))
          .finally(() => {
            // 任务队列的消费区,利用Promise的finally方法,在异步任务结束后,取出下一个任务执行
            if (this._queueList.length) {
              const nextTask = this._queueList.shift()
              nextTask()
              this._count--
            }
          })
      }
      if (this._count < this._max) {
        // 如果异步任务“并发”未达到上限,立刻执行新创建的任务
        task()
        this._count++
      } else {
        // 将创建的推进任务队列中
        this._queueList.push(task)
      }
    })
  }
  // 清空任务队列
  clearQueue() {
    this._queueList = []
    this._count = 0
  }
}

使用:

假设我们有一个请求方法this.$http.post方法,一般情况下,是这样使用的

function requestDemo(){
    this.$http.post('/xxx/xxx').then(({ data: res }) => {
        //处理返回结果
    }).catch((err) => {
        //处理异常情况
    })
}

现在我们要把它改造成受限制的网络请求,假设并发请求上限设为10个,并起名叫limitRequest.js。实现如下:

// 并发队列
import { LimitPromise } from '@/utils/limit-promise.js'
// 请求上限
const MAX = 10
// 核心控制器
const limitP = new LimitPromise(MAX)
//请求方法
function requestDemo(){
  this.$http.post('/xxx/xxx').then(({ data: res }) => {
        //处理返回结果
    }).catch((err) => {
        //处理异常情况
    })
}
//执行
function run(){
  for(let i=0;i<100;i++){
    // 上传 
    limitP.call(this.requestDemo, params1,params2)
  }
}

参考:https://www.cnblogs.com/sunshouguo/p/14844338.html

您可能还喜欢...

发表评论

您的电子邮箱地址不会被公开。