当前位置: 首页 > 知识库问答 >
问题:

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

袁恩
2023-03-14

我有一些代码在一个从数据库中查询出来的列表上进行迭代,并对该列表中的每个元素发出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。所有的都必须进行管理,以便在任何给定的时间内只进行一定数量的promise?

共有3个答案

鲁华灿
2023-03-14

使用数组。原型拼接

while (funcs.length) {
  // 100 at a time
  await Promise.all( funcs.splice(0, 100).map(f => f()) )
}
弓磊
2023-03-14

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

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

然而,这里真的没有必要重新发明轮子。为此可以使用的一个库是es6-promise池。从他们的例子来看:

// On the Web, leave out this line and use the script tag above instead. 
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)
})
法和硕
2023-03-14

P-极限

我已经比较了promise并发限制与自定义脚本、蓝鸟、es6-promise池和p-限制。我相信p-Limited有最简单、最精简的实现来满足这种需求。看他们的留档。

要求

要与异步兼容,例如

  • ECMAScript 2017(版本8)
  • 节点版本

我的例子

在这个例子中,我们需要为数组中的每个URL运行一个函数(比如,可能是一个应用编程接口请求)。在这里,这被称为finchData()。如果我们有成千上万个项目要处理,那么并发对于节省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);
})();

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

 类似资料:
  • 问题内容: 我有一些代码遍历从数据库中查询出来的列表,并对该列表中的每个元素进行HTTP请求。该列表有时可能是一个相当大的数目(成千上万个),并且我想确保我不会遇到具有成千上万个并发HTTP请求的Web服务器。 该代码的缩写版本目前看起来像这样… 该代码在节点4.3.2上运行。重申一下,是否可以进行管理,以便在任何给定时间仅进行一定数量的承诺? 问题答案: 请注意,创建诺言本身不会触发诺言开始工作

  • 问题内容: 复制列表的最佳方法是什么?我知道以下方法,哪种更好?还是有另一种方法? 问题答案: 如果要浅拷贝(不复制元素),请使用: 如果要进行深层复制,请使用复制模块:

  • 我遇到了一个问题。我的网页有一个控件。值更改后(通过选择不同的值),页面将刷新并呈现内容。 下面是我的代码: 第二部分:

  • 问题内容: Java是我选择的编程语言之一。尽管将应用程序分发给最终用户,但我总是遇到问题。 为用户提供JAR并不总是像我想要的那样友好,并且使用Java WebStart要求我维护Web服务器。 分发Java应用程序的最佳方法是什么?如果Java应用程序需要在用户计算机上安装工件,该怎么办?有没有好的Java安装/打包系统? 问题答案: 有多种解决方案,取决于你的发行要求。 只是用一个jar。这

  • 问题内容: 我刚刚完成了将应用程序从Windows移植到Linux的工作。 我必须创建该应用程序的安装程序。 该应用程序 不是 开源的=>我应该分发该应用程序的二进制文件(可执行文件,几个.so文件,帮助文件和图像)。 我不喜欢第一种方法(RPM和DEB软件包),因为我不想为不同的Linux发行版保留不同的软件包。 为Linux分发二进制应用程序的 最佳方法 是什么? 问题答案: 经过几次使用商业

  • 问题内容: 在Clojure中制作 GUI的最佳方法是什么? 有一些功能性Swing或SWT包装器的示例吗?还是与JavaFX声明性GUI描述进行了某些集成,可以使用某些宏轻松地将它们包装到s表达式中? 有教程吗? 问题答案: 我会谦虚地建议跷跷板。 这是一个基于REPL的教程,假定您没有Java或Swing知识。 跷跷板很像@tomjen的建议。这是“你好,世界”: 这是@Abhijith和@d