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

2022-08-30 01:55:01

我有一些代码正在迭代从数据库中查询的列表,并为该列表中的每个元素发出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 */});

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


答案 1

P 极限

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

要求

与示例中的异步兼容

我的例子

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

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);
})();

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


答案 2

Array.prototype.splice

while (funcs.length) {
  // 100 at a time
  await Promise.all( funcs.splice(0, 100).map(f => f()) )
}