需求:
- 设置最大请求数量,当前请求数量,待执行队列
- 调用时,创建一个新任务,然后判断是否达到最大请求数量,若达到则将任务追加到待执行队列,否则,则直接执行该任务。并返回Promise
- 创建任务时,需要返回一个函数,当该任务开始执行则当前数量加一。当任务执行完毕时使用finally,当前数量减一,并从待执行队列中取出新任务执行
实现:
/* 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) } } }
使用:
假设我们有一个请求方法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) } }