vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue并发控制

一文分享4种Vue并发控制的实战方案

作者:前端那点事

在Vue项目开发中,经常会遇到需要同时发起几十个请求的场景,本文结合Vue2/Vue3实战,提供4种主流并发控制方案,覆盖不同场景,可直接落地使用,轻松管控几十个请求的并发逻辑,希望对大家有所帮助

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

一、并发控制核心逻辑

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

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

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

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

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

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

// 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可直接适配)

<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通用)

// 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组件中使用

<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通用)

// 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组件中使用

<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通用)

// 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适配差异(关键注意点)

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

五、总结

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

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

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

以上就是一文分享4种Vue并发控制的实战方案的详细内容,更多关于Vue并发控制的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文