Vue并发控制|几十个请求高效管控(实战方案+可运行代码)

在Vue项目开发中,经常会遇到需要同时发起几十个请求的场景(如批量数据查询、批量提交、页面初始化加载多接口数据)。若直接同时发起所有请求,会导致网络拥堵、接口超时、浏览器卡顿,甚至触发后端接口限流,影响用户体验和系统稳定性。本文结合Vue2/Vue3实战,提供4种主流并发控制方案,覆盖不同场景,可直接落地使用,轻松管控几十个请求的并发逻辑。

一、并发控制核心逻辑

并发控制的核心是:限制同一时间发起的请求数量,将几十个请求分批次、有序执行,避免一次性占用过多网络资源。核心要点的2个:

  • 控制并发数:根据后端接口承载能力和浏览器限制,合理设置并发数(通常4-6个,过多易拥堵,过少效率低);
  • 有序执行:分批次发起请求,上一批请求完成(成功/失败)后,再发起下一批,确保请求有序且不拥堵;
  • 异常兼容:处理单个请求失败、超时场景,避免单个请求失败导致整个并发流程中断。

以下方案均适配Vue2/Vue3,基于Axios请求库(Vue项目主流请求工具),可直接复制到项目中修改使用。

二、4种实战并发控制方案(按推荐度排序)

方案一:并发池控制(最推荐,灵活高效,适配所有场景)

核心思路:封装一个并发池工具,将所有请求放入队列,限制同时执行的请求数量,当某个请求完成后,自动从队列中取出下一个请求执行,循环直至所有请求完成。该方案灵活可控,可处理成功/失败回调、超时控制,是几十个请求并发管控的最优选择。

1. 封装并发池工具(Vue2/Vue3通用)

javascript 复制代码
// utils/requestPool.js
import axios from 'axios';

// 极简版并发池(核心功能:限制并发、处理超时、返回结果)
export async function requestPool(requestList, limit = 4, timeout = 10000) {
  const result = [];
  let running = 0;
  let queue = [...requestList];

  const runRequest = async () => {
    if (queue.length === 0 && running === 0) return result;
    while (running < limit && queue.length > 0) {
      running++;
      const requestFn = queue.shift();
      const index = requestList.length - queue.length - running;
      try {
        const res = await Promise.race([
          requestFn(),
          new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), timeout))
        ]);
        result[index] = { success: true, data: res.data };
      } catch (error) {
        result[index] = { success: false, error: error.message };
      } finally {
        running--;
        await runRequest();
      }
    }
  };
  await runRequest();
  return result;
}

// 极简请求函数(按需修改url和参数)
export function createRequestFn(id) {
  return () => axios({ url: `/api/data/${id}`, method: 'get', timeout: 10000 });
}

2. Vue组件中使用(Vue3示例,Vue2可直接适配)

xml 复制代码
<template>
  <div>
    <button @click="handleBatchRequest">发起30个并发请求</button>
    <div class="result">成功:{{ successCount }} 个 | 失败:{{ failCount }} 个</div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { requestPool, createRequestFn } from '@/utils/requestPool';

const successCount = ref(0);
const failCount = ref(0);

// 极简使用示例(30个请求,并发数5)
const handleBatchRequest = async () => {
  const requestList = Array.from({ length: 30 }, (_, i) => createRequestFn(i + 1));
  const results = await requestPool(requestList, 5);
  successCount.value = results.filter(item => item.success).length;
  failCount.value = results.filter(item => !item.success).length;
};
</script>

<style scoped>
.result { margin-top: 20px; font-size: 14px; color: #333; }
</style>

方案一优势与适配场景

  • 优势:灵活可控,可自定义并发数、超时时间;单个请求失败不影响整体流程;请求结果顺序与发起顺序一致;代码复用性强,可全局调用。
  • 适配场景:几十个请求的批量查询、批量提交、页面初始化多接口加载等所有场景(最推荐)。

方案二:分批次请求(简单易实现,适合对顺序要求高的场景)

核心思路:将几十个请求分成若干批次,每批次发起固定数量的请求(如每批5个),等待当前批次所有请求完成后,再发起下一批。实现简单,无需复杂封装,适合对请求顺序有严格要求的场景(如下一批请求依赖上一批请求结果)。

1. 封装分批次请求工具(Vue2/Vue3通用)

javascript 复制代码
// utils/batchRequest.js
import axios from 'axios';

/**
 * 分批次请求控制
 * @param {Array} requestList - 请求列表(每个元素是请求参数,如id)
 * @param {Number} batchSize - 每批请求数量(默认5个)
 * @returns {Promise} - 所有请求结果数组
 */
export async function batchRequest(requestList, batchSize = 5) {
  const result = [];
  // 计算总批次
  const totalBatch = Math.ceil(requestList.length / batchSize);

  // 循环发起每批次请求
  for (let i = 0; i < totalBatch; i++) {
    // 截取当前批次的请求参数
    const currentBatch = requestList.slice(i * batchSize, (i + 1) * batchSize);
    // 发起当前批次的所有请求(并行)
    const batchResult = await Promise.allSettled(
      currentBatch.map(id => 
        axios({
          url: `/api/data/${id}`,
          method: 'get',
          timeout: 10000
        }).then(res => ({ success: true, data: res.data }))
        .catch(err => ({ success: false, error: err.message }))
      )
    );
    // 将当前批次结果存入总结果
    result.push(...batchResult);
  }

  return result;
}

2. Vue组件中使用

xml 复制代码
<script setup>
import { ref } from 'vue';
import { batchRequest } from '@/utils/batchRequest';

const successCount = ref(0);
const failCount = ref(0);

const handleBatchRequest = async () => {
  // 生成30个请求参数(如id数组)
  const requestList = Array.from({ length: 30 }, (_, i) => i + 1);
  
  // 分批次请求,每批5个
  const results = await batchRequest(requestList, 5);
  
  // 处理结果
  successCount.value = results.filter(item => item.success).length;
  failCount.value = results.filter(item => !item.success).length;
};
</script>

方案二优势与适配场景

  • 优势:实现简单,无需复杂封装;请求批次清晰,顺序可控;适合下一批请求依赖上一批结果的场景。
  • 适配场景:对请求顺序有要求、批量提交且需分批校验的场景(如分批提交表单数据,上一批通过再提交下一批)。

方案三:Axios拦截器控制并发(全局管控,适合简单场景)

核心思路:通过Axios的请求拦截器和响应拦截器,维护一个"正在执行的请求"计数器,当计数器达到并发限制时,将后续请求存入队列,等待正在执行的请求完成后,再依次发起。适合简单场景,无需在组件中单独处理,全局统一管控。

1. 全局配置Axios并发控制(Vue2/Vue3通用)

ini 复制代码
// utils/axiosConfig.js
import axios from 'axios';

// 并发限制数
const CONCURRENT_LIMIT = 4;
// 正在执行的请求计数器
let requestCount = 0;
// 请求队列
const requestQueue = [];

// 创建Axios实例
const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
});

// 请求拦截器:控制并发
service.interceptors.request.use(
  config => {
    return new Promise(resolve => {
      // 若当前请求数未达限制,直接发起请求
      if (requestCount < CONCURRENT_LIMIT) {
        requestCount++;
        resolve(config);
      } else {
        // 达到限制,存入请求队列
        requestQueue.push(resolve);
      }
    });
  },
  error => {
    return Promise.reject(error);
  }
);

// 响应拦截器:请求完成后,从队列中取出下一个请求
service.interceptors.response.use(
  response => {
    // 请求完成,计数器减1
    requestCount--;
    // 若队列中有请求,取出并执行
    if (requestQueue.length > 0) {
      const resolve = requestQueue.shift();
      requestCount++;
      resolve(service.defaults);
    }
    return response;
  },
  error => {
    // 失败也需计数器减1,避免队列卡住
    requestCount--;
    if (requestQueue.length > 0) {
      const resolve = requestQueue.shift();
      requestCount++;
      resolve(service.defaults);
    }
    return Promise.reject(error);
  }
);

export default service;

2. Vue组件中使用

ini 复制代码
<script setup>
import { ref } from 'vue';
import request from '@/utils/axiosConfig';

const successCount = ref(0);
const failCount = ref(0);

// 直接发起30个请求,Axios拦截器自动控制并发
const handleBatchRequest = async () => {
  const requestList = [];
  for (let i = 1; i <= 30; i++) {
    requestList.push(
      request({
        url: `/api/data/${i}`,
        method: 'get'
      }).then(res => ({ success: true, data: res.data }))
      .catch(err => ({ success: false, error: err.message }))
    );
  }

  // 等待所有请求完成
  const results = await Promise.allSettled(requestList);
  successCount.value = results.filter(item => item.success).length;
  failCount.value = results.filter(item => !item.success).length;
};
</script>

方案三优势与适配场景

  • 优势:全局统一管控,组件中无需单独处理并发逻辑;侵入性低,原有请求代码无需修改;实现简单,适合快速落地。
  • 适配场景:项目中所有批量请求需统一控制并发、无需个性化并发配置的简单场景。

方案四:使用第三方库(高效快捷,适合复杂场景)

核心思路:借助成熟的第三方库(如p-limit),快速实现并发控制,无需自己封装工具,适合复杂场景(如并发数动态调整、请求优先级控制)。p-limit轻量、易用,是前端并发控制的常用库。

1. 安装与使用(Vue2/Vue3通用)

typescript 复制代码
// 1. 安装依赖
// npm install p-limit --save

// 2. 组件中使用
<script setup>
import { ref } from 'vue';
import axios from 'axios';
import pLimit from 'p-limit';

// 设置并发限制数为4
const limit = pLimit(4);
const successCount = ref(0);
const failCount = ref(0);

const handleBatchRequest = async () => {
  // 生成30个请求函数,并用p-limit包装
  const requestList = [];
  for (let i = 1; i <= 30; i++) {
    // 用limit包装请求函数,限制并发
    requestList.push(
      limit(() => 
        axios({
          url: `/api/data/${i}`,
          method: 'get',
          timeout: 10000
        }).then(res => ({ success: true, data: res.data }))
        .catch(err => ({ success: false, error: err.message }))
      )
    );
  }

  // 等待所有请求完成
  const results = await Promise.allSettled(requestList);
  successCount.value = results.filter(item => item.success).length;
  failCount.value = results.filter(item => !item.success).length;
};
</script>

方案四优势与适配场景

  • 优势:无需自己封装,高效快捷;支持动态调整并发数、请求优先级;成熟稳定,适配复杂并发场景。
  • 适配场景:复杂并发需求(如动态调整并发数、设置请求优先级)、不想自己封装工具的场景。

三、Vue2与Vue3适配差异(关键注意点)

  • 请求工具:两者均使用Axios,配置方式完全一致,无差异;
  • 组件写法:Vue3使用组合式API(setup语法),Vue2使用选项式API(methods中编写逻辑),核心并发控制逻辑完全一致;
  • 环境变量:Vue3使用import.meta.env,Vue2使用process.env,修改Axios baseURL时需注意适配;
  • 第三方库:p-limit等库适配所有Vue版本,无差异。

四、避坑指南(高频问题)

  • 并发数设置:避免设置过大(如超过10个),否则会导致网络拥堵、后端限流;建议设置4-6个,根据后端接口承载能力调整;
  • 超时控制:必须为单个请求设置超时时间,避免某个请求长时间挂起,导致整个并发流程卡住;
  • 失败处理:使用Promise.allSettled(而非Promise.all),避免单个请求失败导致整个并发流程中断;
  • 请求顺序:并发池和分批次方案可保证请求结果顺序与发起顺序一致,Axios拦截器方案无法保证顺序(需额外处理);
  • 内存占用:几十个请求并发时,避免存储过多请求结果,可按需处理结果(如边请求边渲染),减少内存占用。

五、总结

针对Vue中几十个请求的并发控制,4种方案各有适配场景,可根据项目需求灵活选择:

  1. 并发池控制:最推荐,灵活可控、适配所有场景,兼顾易用性和扩展性;
  2. 分批次请求:适合对请求顺序有要求、下一批依赖上一批结果的场景;
  3. Axios拦截器:适合全局统一管控、无需个性化配置的简单场景;
  4. 第三方库:适合复杂场景、不想自己封装工具的场景。

实际开发中,建议优先使用"并发池控制"方案,既能灵活控制并发数、处理异常,又能保证请求顺序,可直接复制本文代码,修改请求地址和参数即可快速落地,轻松解决几十个请求的并发难题。

相关推荐
妄想出头的工业炼药师2 小时前
后端优化MS mapping
前端
前端那点事2 小时前
Vue大批量接口请求优化|告别卡顿、超时!前端落地实战指南
前端·vue.js
史迪仔01122 小时前
[QML] Qt Quick Dialogs 模块使用指南
开发语言·前端·c++·qt
oy_mail2 小时前
spring-boot-starter和spring-boot-starter-web的关联
前端
空中海2 小时前
第四章:Vue Router
前端·javascript·vue.js
竹林8182 小时前
从零集成RainbowKit:我如何在一个周末搞定多链钱包连接并填平三个大坑
前端·javascript
2601_953465612 小时前
M3U8 在线播放器:无需安装,一键调试 HLS 直播流
开发语言·前端·javascript·开发工具·m3u8·m3u8在线播放
Ruihong2 小时前
你写的是 Vue,跑起来是纯 React?这是什么黑科技
vue.js·react.js·面试
风止何安啊2 小时前
【前端续命术】请求总失败?给你的 AJAX 装上 “不死鸟” 重试 Buff
前端·javascript·面试