axios控制并发请求

568 阅读2分钟

限制axios并发请求(TypeScript)

假设有一种场景,用户需要同时上传1000张图片,每张图片都需要单独发送post请求,但是浏览器或服务器会对并发请求数进行限制,如果前端一次发送的请求超出限制可能会报错。所以需要对前端并发请求数进行限制。

这里把异步任务封装成Promise。

/** @format */

/**
 * 封装axios并发请求数
 */
export default class LimitPromise {
  private _max: number;
  private _count: number;
  private _taskQueue: any[];

  constructor(max: number) {
    // 异步任务“并发”上限
    this._max = max || 6;
    // 当前正在执行的任务数量
    this._count = 0;
    // 等待执行的任务队列
    this._taskQueue = [];
  }

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

  /**
   * 创建一个任务
   * @param caller 实际执行的函数
   * @param args 执行函数的参数
   * @param resolve
   * @param reject
   * @returns {Function} 返回一个任务函数
   * @private
   */
  _createTask(
    caller: (...arg: any[]) => any,
    resolve: (value: any | PromiseLike<any>) => void,
    reject: (reason?: any) => void
  ) {
    return () => {
      // 实际上是在这里调用了异步任务,并将异步任务的返回(resolve和reject)抛给了上层
      caller()
        .then(resolve)
        .catch(reject)
        .finally(() => {
          // 任务队列的消费区,利用Promise的finally方法,在异步任务结束后,取出下一个任务执行
          this._count--;
          if (this._taskQueue.length) {
            const task = this._taskQueue.shift();
            task();
          }
        });
      this._count++;
    };
  }
}

复制代码

在axios配置文件使用封装的LimitPromise 类封装post方法:

import LimitPromise from './limitReq';
import axios, { AxiosRequestConfig } from 'axios';

const limtReq = new LimitPromise(6);
export const limitPost = (
  url: string,
  data?: any,
  config?: AxiosRequestConfig,
  resolve?: (value: any | PromiseLike<any>) => void,
  reject?: (reason?: any) => void
) =>
  limtReq
    .call(() => axios.post(url, data, config))
    .then(resolve)
    .catch(reject);
复制代码

(需要其它方法如get、put等可根据上面封装) 接下来直接将原来的axios.post请求改为limitPost即可