商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Node.js中如何实现并发控制

Node.js中如何实现并发控制

  发布于2026-07-06 阅读(0)

扫一扫,手机访问

在Node.js的世界里,异步操作几乎无处不在,而如何优雅地控制并发——既要保证效率,又不能把系统搞崩——是每个开发者迟早要面对的问题。方法其实不少,关键是根据具体场景选对那个趁手的工具。

Node.js中如何实现并发控制

先来看看最常见的几种做法。

1. 使用async库

如果你还在用回调风格写异步代码,或者维护着老项目,async库是个很实用的选择。它提供了parallelserieswaterfall等函数,让我们能清晰地编排多个异步任务的执行顺序。比如用async.parallel来并发执行三个任务:

const async = require('async');

const task1 = (callback) => {
  // 任务1的代码
  callback(null, '结果1');
};

const task2 = (callback) => {
  // 任务2的代码
  callback(null, '结果2');
};

const task3 = (callback) => {
  // 任务3的代码
  callback(null, '结果3');
};

async.parallel([task1, task2, task3], (err, results) => {
  if (err) {
    console.error('发生错误:', err);
  } else {
    console.log('任务结果:', results);
  }
});

这种方式的好处是直观、底层兼容性好,缺点是需要层层回调,代码一多就不好维护了。

2. 使用Promise.all

ES6之后,Promise成了异步编程的主流。Promise.all接受一个Promise数组,当所有Promise都resolve时,返回一个包含所有结果的数组;只要有一个reject,整体就立即失败。同样是三个任务:

const promise1 = new Promise((resolve, reject) => {
  resolve('结果1');
});
const promise2 = new Promise((resolve, reject) => {
  resolve('结果2');
});
const promise3 = new Promise((resolve, reject) => {
  resolve('结果3');
});

Promise.all([promise1, promise2, promise3])
  .then((results) => {
    console.log('任务结果:', results);
  })
  .catch((error) => {
    console.error('发生错误:', error);
  });

相比回调,Promise的链式调用清晰很多,而且支持错误冒泡。不过要注意,Promise.all是“全有或全无”的——任何一个任务失败,其他任务的结果就丢了(虽然它们可能还在执行)。

3. 使用async/await

async/await本质上是Promise的语法糖,但写起来更像同步代码,可读性极佳。把上面的例子改成async/await:

async function runTasks() {
  try {
    const result1 = await promise1;
    const result2 = await promise2;
    const result3 = await promise3;
    console.log('任务结果:', [result1, result2, result3]);
  } catch (error) {
    console.error('发生错误:', error);
  }
}

runTasks();

注意:这里如果写成依次await,其实是串行执行,而不是并发。要实现真正的并发,通常需要先启动所有Promise(比如存入数组),再用await Promise.all(...)。这个细节容易被忽略,但很关键。

4. 使用信号量(Semaphore)

前面几种方法都是“全部并发”或“全部串行”,但在实际业务中,我们经常需要限制同时执行的任务数量——比如同时最多发5个网络请求,避免把下游服务打爆。这时候就需要信号量。

在Node.js中,bottleneck是一个很成熟的限流库。它的用法非常简洁:

const Bottleneck = require('bottleneck');

const limiter = new Bottleneck({
  maxConcurrent: 2,   // 同时最多执行2个任务
  minTime: 100        // 每个任务之间至少间隔100毫秒
});

const task1 = () => { /* 任务1的代码 */ };
const task2 = () => { /* 任务2的代码 */ };
const task3 = () => { /* 任务3的代码 */ };

limiter.schedule(task1);
limiter.schedule(task2);
limiter.schedule(task3);

除了bottleneck,你还可以用async.queuep-limit等方案,思路大同小异。信号量的核心价值在于控制资源水平,避免系统过载,这在生产环境中几乎是必备技能。

说到底,没有银弹。追求极致性能就上Promise.all并合理控制并发数;代码可维护性优先就用async/await配合限流;如果是遗留项目或需要精细控制任务依赖,async库依然是可靠的选择。根据业务场景灵活组合,才是最佳实践。

本文转载于:https://www.yisu.com/ask/78141746.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注