2016-11-16 101 views
11

我有一些代碼遍歷從數據庫查詢出來的列表,併爲該列表中的每個元素髮出HTTP請求。該列表有時可能是一個相當大的數字(以千計),並且我想確保我沒有訪問具有數千個併發HTTP請求的Web服務器。使用ES6的Promise.all()時限制併發性的最佳方式是什麼?

這段代碼的縮寫版本目前看起來是這樣的......

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,以便在任何特定時間只有一定數量的承諾正在進行中?

+0

[限於承諾正在運行的併發]的可能重複(http://stackoverflow.com/q/38778723/1048572) – Bergi

+2

不要忘記['Promise.all '管理承諾進展](http://stackoverflow.com/a/30823708/1048572) - 承諾自己做,'Promise.all'只是等待他們。 – Bergi

+0

避免['Promise' constructor antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi

回答

15

請注意,Promise.all()不會觸發承諾開始他們的工作,創造承諾本身。

考慮到這一點,一個解決方案就是檢查承諾何時解決,是否應該啓動新的承諾,或者您是否已經達到極限。

但是,真的沒有必要在這裏重新發明輪子。 One library that you could use for this purpose is 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) 
}) 
4

而不是使用承諾限制HTTP請求,使用節點的內置http.Agent.maxSockets。這消除了使用庫或編寫自己的池化代碼的要求,並具有更多控制權限的優勢。

agent.maxSockets

默認設置爲無窮大。確定代理每個源可以打開多少個併發套接字。 Origin可以是'host:port'或'host:port:localAddress'組合。

例如:

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

如果進行多次請求相同的起源,它也可能會受益您設置keepAlive爲true(見上文的詳細信息文檔)。

+3

儘管如此,立即創建數以千計的閉包和彙集套接字看起來效率不高? – Bergi

1

bluebird的Promise.map可以採用併發選項來控制並行運行多少個promise。有時它比.all更容易,因爲您不需要創建promise數組。

const Promise = require('bluebird') 

function getCounts() { 
    return Promise.map(users, user => { 
    return new Promise(resolve => { 
     remoteServer.getCount(user) // makes an HTTP request 
     .then(() => { 
     /* snip */ 
     resolve(); 
     }); 
    }); 
    }, {concurrency: 10}); // <---- at most 10 http requests at a time 
} 

裁判:http://bluebirdjs.com/docs/api/promise.map.html

相關問題