使用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 */}); 

此代码在节点4.3.2上运行。 重申,可以Promise.all ,所有的时间都只有一定数量的承诺在进行。

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

考虑到这一点,一个解决scheme就是检查一个承诺是否解决,是否应该启动一个新的承诺,或者你是否已经达到了极限。

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

 // 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) }) 

使用节点的内置http.Agent.maxSockets ,而不是使用promise来限制http请求。 这消除了使用库或者编写自己的池代码的需求,并且有更多的控制权限来控制你的限制。

agent.maxSockets

默认设置为无穷大。 确定代理每个源可以打开多less个并发套接字。 起源可以是“主机:端口”或“主机:端口:本地地址”组合。

例如:

 var http = require('http'); var agent = new http.Agent({maxSockets: 5}); // 5 concurrent connections per origin var request = http.request({..., agent: agent}, ...); 

如果向同一个源发出多个请求,那么将keepAlive设置为true也可能会有所帮助(请参阅上面的文档以获取更多信息)。