如何实现现代JavaScript Promise并发控制

来源:网站主作者:北京GEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《如何实现现代JavaScript Promise并发控制》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何实现现代JavaScript Promise并发控制》有用,将其分享出去将是对创作者最好的鼓励。

在现代JavaScript开发中,异步操作是非常常见的场景,当我们需要同时处理多个异步任务时,如果不做并发控制,可能会导致资源占用过高、请求过载等问题。Promise作为JavaScript处理异步的核心方案,提供了多种并发控制的方式。

Promise原生并发方法对比

JavaScript内置的Promise对象提供了几个用于并发处理异步任务的方法,不同方法的适用场景有明显差异,下面我们来逐一分析。

Promise.all

Promise.all接收一个Promise数组,当所有Promise都成功时返回所有结果组成的数组,只要有一个Promise失败就直接进入catch回调,适合需要所有任务都成功才能继续后续逻辑的场景。

// 模拟异步请求函数
function asyncTask(id, delay, success = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (success) {
        resolve(`任务${id}完成,耗时${delay}ms`);
      } else {
        reject(`任务${id}失败`);
      }
    }, delay);
  });
}

// 使用Promise.all并发执行三个任务
Promise.all([
  asyncTask(1, 1000),
  asyncTask(2, 1500),
  asyncTask(3, 800)
]).then(results => {
  console.log('所有任务都成功:', results);
}).catch(err => {
  console.log('有任务失败:', err);
});

Promise.allSettled

Promise.allSettled同样接收Promise数组,它会等待所有Promise都完成(不管成功还是失败),最终返回一个包含每个任务状态的对象数组,适合需要统计所有任务执行结果的场景,不需要因为单个任务失败就中断整体流程。

Promise.allSettled([
  asyncTask(1, 1000, true),
  asyncTask(2, 1500, false),
  asyncTask(3, 800, true)
]).then(results => {
  console.log('所有任务执行完毕,结果如下:');
  results.forEach(item => {
    if (item.status === 'fulfilled') {
      console.log(`成功: ${item.value}`);
    } else {
      console.log(`失败: ${item.reason}`);
    }
  });
});

Promise.race

Promise.race返回第一个完成(不管是成功还是失败)的Promise结果,适合需要设置超时逻辑或者只需要获取最快返回结果的场景。

// 模拟超时逻辑
function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) => {
      setTimeout(() => {
        reject('请求超时');
      }, timeout);
    })
  ]);
}

const task = asyncTask(1, 2000, true);
withTimeout(task, 1500).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err); // 输出: 请求超时
});

自定义并发控制队列实现

上面的原生方法要么是所有任务同时发起,要么是只取最快结果,无法满足限制最大并发数量的需求。比如我们需要同时请求100个接口,但是最多只能同时发起5个请求,避免服务端压力过大,这时候就需要手动实现并发控制队列。

实现思路

  • 维护一个任务队列,存放所有需要执行的异步任务
  • 维护一个正在执行的任务数组,记录当前正在运行的任务
  • 设置最大并发数,初始时取出最大并发数个任务执行
  • 当有任务执行完成时,从正在执行数组中移除该任务,再从任务队列中取出新任务执行
  • 直到所有任务都执行完毕,返回所有结果

完整代码实现

/**
 * Promise并发控制函数
 * @param {Array<Function>} tasks 异步任务数组,每个元素是返回Promise的函数
 * @param {number} maxConcurrency 最大并发数
 * @returns {Promise<Array>} 所有任务的结果数组
 */
function promiseConcurrentControl(tasks, maxConcurrency) {
  return new Promise((resolve) => {
    // 校验参数
    if (!Array.isArray(tasks) || tasks.length === 0) {
      resolve([]);
      return;
    }
    if (maxConcurrency <= 0) {
      maxConcurrency = 1;
    }

    const results = []; // 存储所有任务结果
    const executing = []; // 存储正在执行的任务
    let currentIndex = 0; // 当前任务索引

    // 执行单个任务的函数
    function runTask() {
      // 如果所有任务都执行完了,判断是否需要结束
      if (currentIndex >= tasks.length && executing.length === 0) {
        resolve(results);
        return;
      }

      // 如果还有任务没执行,且当前执行中的任务数小于最大并发数,就继续执行新任务
      while (currentIndex < tasks.length && executing.length < maxConcurrency) {
        const taskIndex = currentIndex;
        const task = tasks[currentIndex];
        currentIndex++;

        // 执行任务,保存promise
        const taskPromise = task().then(res => {
          results[taskIndex] = {
            status: 'fulfilled',
            value: res
          };
        }).catch(err => {
          results[taskIndex] = {
            status: 'rejected',
            reason: err
          };
        }).finally(() => {
          // 任务完成后,从正在执行的数组中移除
          const execIndex = executing.indexOf(taskPromise);
          if (execIndex > -1) {
            executing.splice(execIndex, 1);
          }
          // 继续执行下一个任务
          runTask();
        });

        executing.push(taskPromise);
      }
    }

    // 启动执行
    runTask();
  });
}

// 测试自定义并发控制函数
const testTasks = [];
for (let i = 0; i < 10; i++) {
  testTasks.push(() => asyncTask(i + 1, Math.random() * 1000 + 500));
}

promiseConcurrentControl(testTasks, 3).then(res => {
  console.log('所有任务执行完毕,结果:');
  res.forEach(item => {
    if (item.status === 'fulfilled') {
      console.log(`成功: ${item.value}`);
    } else {
      console.log(`失败: ${item.reason}`);
    }
  });
});

实际场景应用建议

在实际开发中,我们可以根据需求选择合适的并发控制方案:

  • 如果多个异步任务相互依赖,必须全部成功才能继续,优先使用Promise.all
  • 如果需要获取所有任务的执行结果,不管成功失败,使用Promise.allSettled
  • 如果需要设置请求超时或者只需要最快返回的结果,使用Promise.race
  • 如果需要限制同时执行的异步任务数量,比如批量上传文件、批量请求接口,使用自定义的并发控制队列

合理控制Promise的并发数量,可以有效避免浏览器或者Node.js环境的资源耗尽问题,提升应用的健壮性和用户体验。

JavaScriptPromise并发控制异步编程修改时间:2026-07-17 02:51:39

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。