使用 ES6 的 Promise.all() 时限制并发的最佳方法是什么?

新手上路,请多包涵

我有一些代码迭代从数据库中查询出的列表,并为该列表中的每个元素发出 HTTP 请求。该列表有时可能是一个相当大的数字(数千个),我想确保我不会访问具有数千个并发 HTTP 请求的 Web 服务器。

此代码的缩写版本目前看起来像这样……

 function getCounts() {
  return users.map(user => {
    return new Promise(resolve => {
      remoteServer.getCount(user) // makes an HTTP request
      .then(() => {
        /* snip */
        resolve();
      });
    });
  });
}

Promise.all(getCounts()).then(() => { /* snip */});

此代码在 Node 4.3.2 上运行。重申一下,能否对 Promise.all 进行管理,以便在任何给定时间只有一定数量的承诺在进行中?

原文由 Chris 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 803
2 个回答

请注意, Promise.all() 不会触发开始工作的承诺,而是创建承诺本身。

考虑到这一点,一种解决方案是在承诺解决时检查是否应该开始新的承诺,或者您是否已经达到极限。

不过,这里真的没有必要重新发明轮子。 您可以为此目的使用的一个库是 es6-promise-pool 。从他们的例子:

 var PromisePool = require('es6-promise-pool')

var promiseProducer = function () {
  // Your code goes here.
  // If there is work left to be done, return the next work item as a promise.
  // Otherwise, return null to indicate that all promises have been created.
  // Scroll down for an example.
}

// The number of promises to process simultaneously.
var concurrency = 3

// Create a pool.
var pool = new PromisePool(promiseProducer, concurrency)

// Start the pool.
var poolPromise = pool.start()

// Wait for the pool to settle.
poolPromise.then(function () {
  console.log('All promises fulfilled')
}, function (error) {
  console.log('Some promise rejected: ' + error.message)
})

原文由 TimoStaudinger 发布,翻译遵循 CC BY-SA 4.0 许可协议

P-限制

我将 promise 并发限制与自定义脚本、bluebird、es6-promise-pool 和 p-limit 进行了比较。我相信 p-limit 具有满足此需求的最简单、精简的实现。 请参阅他们的文档

要求

在示例中与异步兼容

我的例子

在这个例子中,我们需要为数组中的每个 URL 运行一个函数(比如,可能是一个 API 请求)。这里称为 fetchData() 。如果我们有一个包含数千个项目的数组要处理,并发对于节省 CPU 和内存资源肯定很有用。

 const pLimit = require('p-limit');

// Example Concurrency of 3 promise at once
const limit = pLimit(3);

let urls = [
    "http://www.exampleone.com/",
    "http://www.exampletwo.com/",
    "http://www.examplethree.com/",
    "http://www.examplefour.com/",
]

// Create an array of our promises using map (fetchData() returns a promise)
let promises = urls.map(url => {

    // wrap the function we are calling in the limit function we defined above
    return limit(() => fetchData(url));
});

(async () => {
    // Only three promises are run at once (as defined above)
    const result = await Promise.all(promises);
    console.log(result);
})();

控制台日志结果是您已解决的承诺响应数据的数组。

原文由 Matthew Rideout 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题