首页 > 其他分享 >axios请求并发限制

axios请求并发限制

时间:2023-11-17 16:22:59浏览次数:24  
标签:resolve const 请求 ._ 并发 axios Promise reject return

队列有x个之后执行

正文

在网上看到这么一道题:

2-1

首先来实现一个分割数组的函数~

const group = (list = [], max = 0) => {
  if (!list.length) {
    return list;
  }
  let results = [];
  for (let i = 0, len = list.length; i < len; i += max) {
    results.push(list.slice(i, i + max));
  }
  return results;
};

这里就是根据指定的并发数量来分割数组。主要就是for + slice,这没啥好说的

接下来再来一个用async + await实现的请求集合封装。

Promise.allSettled去执行每一组的请求集合。

Promise.allSettled是一个新的 API,跟Promise.all差不多的用法,也是接受的数组,不过不同的是Promise.allSettled会等所有任务结束之后才会返回结果,而Promise.all只要有一个reject就会返回结果。

const requestHandler = async (groupedUrl = [], callback = () => {}) => {
  if (!groupedUrl.length) {
    callback();
    return groupedUrl;
  }
  const newGroupedUrl = groupedUrl.map((fn) => fn());
  const resultsMapper = (results) => results.map(callback);
  const data = await Promise.allSettled(newGroupedUrl).then(resultsMapper);
  return data;
};

接下来就是主函数

const sendRequest = async (urls = [], max = 0, callback = () => {}) => {
  if (!urls.length) {
    return urls;
  }
  const groupedUrls = group(urls, max);
  const results = [];
  console.log("start !");
  for (let groupedUrl of groupedUrls) {
    try {
      const result = await requestHandler(groupedUrl, callback);
      results.push(result);
      console.log("go");
    } catch {}
  }
  console.log("done !");
  return results;
};

这里就是利用了for + async + await来限制并发。等每次并发任务结果出来之后再执行下一次的任务。

执行下栗子:

const p1 = () =>
  new Promise((resolve, reject) => setTimeout(reject, 1000, "p1"));
const p2 = () => Promise.resolve(2);
const p3 = () =>
  new Promise((resolve, reject) => setTimeout(resolve, 2000, "p3"));
const p4 = () => Promise.resolve(4);
const p5 = () =>
  new Promise((resolve, reject) => setTimeout(reject, 2000, "p5"));
const p6 = () => Promise.resolve(6);
const p7 = () =>
  new Promise((resolve, reject) => setTimeout(resolve, 1000, "p7"));
const p8 = () => Promise.resolve(8);
const p9 = () =>
  new Promise((resolve, reject) => setTimeout(reject, 1000, "p9"));
const p10 = () => Promise.resolve(10);
const p11 = () =>
  new Promise((resolve, reject) => setTimeout(resolve, 2000, "p10"));
const p12 = () => Promise.resolve(12);
const p13 = () =>
  new Promise((resolve, reject) => setTimeout(reject, 1000, "p11"));
const p14 = () => Promise.resolve(14);

const ps = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14];
sendRequest(ps, 3, ({ reason, value }) => {
  console.log(reason || value);
});

2-2

队列最多有x个

前言:

  1. 浏览器对同一域名下同一时间点的最大连接数做了限制,谷歌是 6 个,其他浏览器可百度查看相关资料。
  2. 浏览器同一时间点内发送的请求过多,会导致请求很慢页面卡顿的情况

解决问题

  1. 封装限制 Promise 异步任务并发请求数

核心函数也就两个。
调用器:就是把真正的执行函数和参数传入,创建返回一个新的 Promise,而这个新 Promise 的什么时候返回,取决于这个异步任务何时被调度。Promise 内部主要就是创建一个任务,判断任务是执行还是入队。
创建任务:实际上就是返回了一个函数,将真正的执行函数放在里面执行。这里利用了 Promise 的 finally 方法,在 finally 中判断是否执行下一个任务,实现任务队列连续消费的地方就是这里。

/**
 * 封装axios并发请求数
 */
class LimitPromise {
  constructor(max) {
    // 异步任务“并发”上限
    this._max = max || 6;
    // 当前正在执行的任务数量
    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._count , this._max, this._taskQueue)
        this._taskQueue.push(task);
      } else {
        // console.log('数组中的对列长度还没超过6个', this._count)
        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', this._taskQueue)
            let task = this._taskQueue.shift();
            task();
          } else {
            // console.log('task count = ', count)
          }
        });
      this._count++;
      // console.log('task run , task count = ', this._count)
    };
  }
}

export default LimitPromise;
  1. 在封装的 axios 文件使用并发数限制
import axios from "axios";
import { message } from "antd";
import qs from "qs";

// 引入上面封装好的并发数限制文件
import LimitPromise from "./limitPromise";

// 并发请求上限
const MAX = 5;
// 调用核心控制器类
const limitP = new LimitPromise(MAX);

//响应时间
axios.defaults.timeout = 300000; // 5 min
axios.defaults.headers.post["Content-Type"] = "application/json";

// request interceptor
axios.interceptors.request.use(
  (config) => {
    config.headers["Content-Type"] = "application/json";
    config.headers["datae-token"] = localStorage.getItem("xyToken");

    //application/x-www-form-urlencoded
    if (config.resType === "form") {
      config.headers["Content-Type"] = "application/x-www-form-urlencoded";
      config.data = qs.stringify(config.data);
      return config;
    }

    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// response interceptor
axios.interceptors.response.use(
  (response) => {
    if (response.status >= 400) {
      // 没登录/过期
      if (response.status === 401) {
        message.error("登录态过期,请重新登录");
        // ...写入自己的代码逻辑和判断
        return;
      }
      return Promise.reject(response);
    }

    return response;
  },
  (error) => {
    if (error.response.status === 401) {
      message.error("登录态过期,请重新登录");
      // ...写入自己的代码逻辑和判断
    } else {
      message.error("网络连接超时");
    }

    return Promise.reject(error);
  }
);

// 导出axios的几种请求方式
export const getP = (url, params, config = {}) => {
  return limitP
    .call(axios.get, url, {
      params: params,
      ...config,
    })
    .then((res) => res.data);
};

export const postP = (url, params, config = {}) => {
  return limitP
    .call(axios.post, url, params, {
      ...config,
    })
    .then((res) => res.data);
};
// 如果还需要其他请求,请结合aixos的api进行相关配置

export default axios;

标签:resolve,const,请求,._,并发,axios,Promise,reject,return
From: https://www.cnblogs.com/wp-leonard/p/17839035.html

相关文章

  • 同时调用多个异步请求
    需求为了减少页面等待时间,现有多个接口,需要同时调用。解决有两种写法:Promise.all([interfaceName1(para1),interfaceName2(para2)]).then().catch()Promise.all(arr)中的参数arr:由接口名称(接口参数)组成的数组;then((res)=>{})中的结果res:接口结果所组成的数组。例1......
  • Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
    今天主要说说如何通过自定义注解的方式,在SpringBoot中来实现AOP切面统一打印出入参日志。小伙伴们可以收藏一波。废话不多说,进入正题!一、先看看切面日志输出效果在看看实现方法之前,我们先看下切面日志输出效果咋样:从上图中可以看到,每个对于每个请求,开始与结束一目了然,并且打印......
  • java RestTemplate 发送post请求
    RestTemplate简介RestTemplate是执行HTTP请求的同步阻塞式的客户端,它在HTTP客户端库(如JDKHttpURLConnection,ApacheHttpComponents,okHttp等)基础封装了更加简单易用的模板方法API。即RestTemplate是一个封装,底层的实现还是java应用开发中常用的一些HTTP客户端。相对于直接使用底层......
  • 升讯威在线客服系统的并发高性能数据处理技术:实现拔网线也不丢消息的高可靠通信(附视频
    我在业余时间开发维护了一款免费开源的升讯威在线客服系统,也收获了许多用户。对我来说,只要能获得用户的认可,就是我最大的动力。客服系统开发过程中,最让我意外的是对TCP/IP协议的认识。过去一直认为TCP/IP是可靠的连接,加上过去开发的软件网络环境比较稳定,很少在这个问题上纠结......
  • 未预编译文件“/default.aspx”,因此不能请求该文件
    未预编译文件“/default.aspx”,因此不能请求该文件。说明:执行当前Web请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。异常详细信息:System.Web.HttpException:未预编译文件“/default.aspx”,因此不能请求该文件。 ......
  • 高并发下如何设计秒杀系统
    #高并发下如何设计秒杀系统本文总结自如果面试遇到秒杀系统,要这样回答。。。​‍秒杀是一种促销活动,在一个时间开放购买,很多用户抢购商品,但只有极少数用户能够购买成功秒杀这种活动商家通常是不赚钱的,用来宣传自己,但这种活动对技术的要求不低,下面总结一下秒杀相关的技术细节......
  • MySQL数据库高并发优化配置
    在Apache,PHP,mysql的体系架构中,MySQL对于性能的影响最大,也是关键的核心部分。对于Discuz!论坛程序也是如此,MySQL的设置是否合理优化,直接影响到论坛的速度和承载量!同时,MySQL也是优化难度最大的一个部分,不但需要理解一些MySQL专业知识,同时还需要长时间的观察统计并且根据经验进......
  • http请求问题
    在建立http请求的时候,一定要注意请求格式:publicstaticJSONObjecthttpRequest(StringrequestUrl,StringrequestMethod,StringoutputStr){JSONObjectjsonObject=null;StringBufferbuffer=newStringBuffer();try{URLurl=newURL(requestUrl);......
  • 服务器未正确处理预检请求,解决办法
    这个错误提示表明浏览器已经阻止了跨域请求,因为服务器未正确处理预检请求。预检请求是浏览器在发送跨域请求之前,先向服务器发送一个OPTIONS请求,以确定服务器是否接受跨域请求,并确定可以使用哪些HTTP方法和请求头。为了解决这个问题,您需要在服务器端添加处理预检请求的代码。......
  • JUC并发编程(终章)各种锁的理解
    各种锁的理解公平锁、非公平锁公平锁:先到先得(不可插队)非公平锁:达者为先(可插队)---------->默认publicReentrantLock(){//默认非公平锁sync=newNonfairSync();}//重载的构造方法,通过fair控制是否公平publicReentrantLock(booleanfair){sync=fair?......