2016-11-16 33 views
11

Mam pewien kod, który jest iteracją na liście, która została przeszukiwana z bazy danych i wysyła żądanie HTTP dla każdego elementu na tej liście. Lista ta może czasami być dość dużą liczbą (w tysiącach) i chciałbym się upewnić, że nie trafię na serwer WWW z tysiącami równoczesnych żądań HTTP.Jaki jest najlepszy sposób ograniczenia współbieżności przy użyciu opcji Promise.all() ES6?

skrócona wersja tego kodu aktualnie wygląda tak ...

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

Ten kod jest uruchomiony na węźle 4.3.2. Aby powtórzyć, czy można zarządzać Promise.all, tak aby w danym momencie realizowana była tylko określona liczba obietnic?

+0

możliwe duplikat [Limit współbieżności obietnicy prowadzony] (http://stackoverflow.com/q/38778723/1048572) – Bergi

+2

Nie zapominaj, że [ 'Promise.all 'nie zarządza obiecującym postępem] (http://stackoverflow.com/a/30823708/1048572) - obietnice robią to same,' Promise.all' tylko czeka na nich. – Bergi

+0

Unikaj konstruktora "Promise" antipattern (http://stackoverflow.com/q/23803743/1048572)! – Bergi

Odpowiedz

15

Należy pamiętać, że Promise.all() nie uruchamia obietnic rozpoczęcia pracy, ponieważ sama tworzy obietnicę.

Mając to na uwadze, jednym z rozwiązań byłoby sprawdzenie, czy obietnica zostanie rozstrzygnięta, czy nowa obietnica powinna zostać uruchomiona, czy też już znajduje się na granicy.

Jednak nie ma potrzeby wymyślać na nowo koła. One library that you could use for this purpose is es6-promise-pool. Z ich przykładów:

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

Zamiast używać obietnic dla ograniczenia żądań HTTP, korzystanie węzeł wbudowanej http.Agent.maxSockets. Eliminuje to konieczność korzystania z biblioteki lub pisania własnego kodu łączącego i ma dodatkową zaletę większą kontrolę nad tym, co ograniczasz.

agent.maxSockets

domyślnie ustawiony na nieskończoność. Określa, ile równoczesnych gniazd może otwierać agent na początek. Origin jest kombinacją "host: port" lub "host: port: localAddress".

Na przykład:

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

przypadku wykonywania wielu żądań do tego samego pochodzenia, może również korzystać na ustawienie keepAlive true (patrz powyższe dokumenty aby uzyskać więcej informacji).

+3

Jednak tworzenie tysięcy zamknięć natychmiast i podłączanie gniazd nie wydaje się być bardzo wydajne? – Bergi

1

Bluebird's Promise.map może wybrać opcję współbieżności, aby kontrolować, ile obietnic powinno być uruchomionych równolegle. Czasami jest to łatwiejsze niż .all, ponieważ nie trzeba tworzyć tablicy obietnicy.

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 
} 

ref: http://bluebirdjs.com/docs/api/promise.map.html