JavaScript并发请求控制实现与优化

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>并发请求控制示例</title>
  <!-- 注意:实际项目中index.js应该包含concurRquest函数的实现 -->
  <script src="./index.js"></script>
</head>
<body>
  <script>
    // 生成测试URL数组
    const urls = Array.from({length: 100}, (_, i) => `http://localhost:3000/api?id=${i + 1}`);
    
    // 调用并发请求函数,最大并发数为12
    concurRquest(urls, 12)
      .then(res => {
        console.log('所有请求完成:', res);
      })
      .catch(error => {
        console.error('请求过程中出错:', error);
      });
  </script>
</body>
</html>
/**
 * 并发请求控制函数
 * @param {string[]} urls 请求的URL数组
 * @param {number} maxNum 最大并发数
 * @returns {Promise<any[]>} 返回一个Promise,resolve时返回所有请求结果的数组
 */
function concurRquest(urls, maxNum) {
  return new Promise((resolve, reject) => {
    // 参数校验
    if (!Array.isArray(urls) || urls.length === 0) {
      resolve([]);
      return;
    }
    
    if (typeof maxNum !== 'number' || maxNum <= 0) {
      reject(new Error('maxNum必须为正数'));
      return;
    }

    const results = []; // 存储所有请求结果
    let count = 0; // 已完成的请求数量
    let index = 0; // 当前要处理的URL索引
    let hasError = false; // 标记是否发生错误

    // 执行单个请求的辅助函数
    async function run() {
      if (hasError) return; // 如果已有错误发生,不再继续新请求
      
      const currentIndex = index++; // 获取当前请求的索引
      
      // 所有URL已处理完毕
      if (currentIndex >= urls.length) {
        return;
      }

      const url = urls[currentIndex];
      
      try {
        console.log(`开始请求: ${url}`);
        const response = await fetch(url);
        
        // 检查响应状态
        if (!response.ok) {
          throw new Error(`请求失败,状态码: ${response.status}`);
        }
        
        // 假设我们想要JSON格式的响应数据
        const data = await response.json();
        results[currentIndex] = data;
      } catch (error) {
        hasError = true; // 标记错误状态
        reject(error); // 立即拒绝整个Promise
        return;
      } finally {
        // 无论成功失败,都增加完成计数
        if (!hasError) {
          count++;
          
          // 所有请求完成
          if (count === urls.length) {
            resolve(results);
          }
          
          // 启动下一个请求
          run();
        }
      }
    }

    // 启动初始批次请求
    const initialConcurrency = Math.min(maxNum, urls.length);
    for (let i = 0; i < initialConcurrency; i++) {
      run();
    }
  });
}

核心原理

  1. 维护一个"请求池",初始时启动最大并发数允许的请求

  2. 每个请求完成后,无论成功失败,都从剩余的URL中取出下一个进行请求

  3. 使用计数器跟踪已完成的请求数量,当所有请求完成时resolve最终的Promise

  4. 使用索引确保返回结果的顺序与输入URL顺序一致

使用场景

  1. 需要批量获取数据的场景

  2. 需要限制同时发起的请求数量以避免浏览器限制

  3. 需要对大量请求结果进行有序处理的场景

注意事项

  1. 根据API特性可能需要调整错误处理逻辑

  2. 对于特别大量的请求,可以考虑分批次处理以避免内存问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值