Użyjesz mniejszej ilości pamięci, jeśli nie masz żadnych obietnic 58k, powiązanych z nimi operacji asynchronicznych i danych wyników aktywnych jednocześnie.
Zamiast tego chcesz uruchomić X operacji na raz, a następnie, gdy jeden zakończy, możesz rozpocząć następny z nigdy więcej niż X w locie w tym samym czasie i nigdy więcej niż X obietnic w użyciu na raz.
Można eksperymentować z odpowiednią wartością X. Wartość 1 to operacje sekwencyjne, ale często można poprawić całkowity czas operacji od końca do końca, stosując wyższą wartość X. Jeśli wszystkie żądania trafiają na ten sam host , X to prawdopodobnie nie więcej niż 5-10 (ponieważ dany host nie może naprawdę zrobić wielu rzeczy naraz i prosząc go o więcej, niż może to zrobić, po prostu spowalnia).
Jeśli każde żądanie dotyczy innego hosta, może być możliwe zwiększenie wartości X. Eksperymenty dadzą optymalną wartość zarówno dla wykorzystania pamięci szczytowej, jak i ogólnej przepustowości i będą w pewnym stopniu zależeć od konkretnych okoliczności.
Bluebird's Promise.map()
ma opcję współbieżności, która zrobi to za Ciebie, ale istnieje również wiele sposobów na kodowanie tylko X w locie w tym samym czasie.
Oto kilka innych przykładów kodujące zarządzania ile są w locie w czasie:
Make several requests to an API that can only handle 20 request a minute
How to execute promises in series?
unable to complete promises due to out of memory
Fire off 1,000,000 requests 100 at a time
How to make it so that I can execute say 10 promises at a time in javascript to prevent rate limits on api calls?
Jeśli nie potrzebują rozwiązane dane, można pozwolić mu być GCed prędzej zastępując go tak:
const p = backgroundScheduler.getClanProfile(clanTags[i], true).then(data => {
return 0; // make resolved value just be a simple number
// so other data is now eligible for GC
});
promiseArray.push(p)
, a tutaj jest prosta implementacja że iteracje tablicę nie więcej niż X żądań w locie w tym samym czasie:
// takes an array of items and a function that returns a promise
// runs no more than maxConcurrent requests at once
function mapConcurrent(items, maxConcurrent, fn) {
let index = 0;
let inFlightCntr = 0;
let doneCntr = 0;
let results = new Array(items.length);
let stop = false;
return new Promise(function(resolve, reject) {
function runNext() {
let i = index;
++inFlightCntr;
fn(items[index], index++).then(function(val) {
++doneCntr;
--inFlightCntr;
results[i] = val;
run();
}, function(err) {
// set flag so we don't launch any more requests
stop = true;
reject(err);
});
}
function run() {
// launch as many as we're allowed to
while (!stop && inflightCntr < maxConcurrent && index < items.length) {
runNext();
}
// if all are done, then resolve parent promise with results
if (doneCntr === items.length) {
resolve(results);
}
}
run();
});
}
58.000 obietnic ?! Brzmi dla mnie tak, jakbyś musiał mieć punkt odcięcia. Jeśli otrzymasz więcej niż X, porzuć niektóre z nich. Jeśli otrzymujesz tyle połączeń, powinieneś rozważyć pewne równoważenie obciążenia i uruchomienie serwera w więcej niż jednym procesie węzła. –
Podejrzewam, że nie jest to możliwe w przypadku rodzimych obietnic, ponieważ nie mają one możliwości dowiedzenia się, że żaden z dołączonych wywołań zwrotnych nie użyje danych (dopóki sama obietnica nie zostanie przypisana do GC). –
W celu uniknięcia przechowywania danych odpowiedzi, można wykonać 'promiseArray.push (p.then (() => 'success'))" To powinno upuścić dane, które obiera obietnica i nadal zwracać użyteczną obietnicę. Powinien. Jestem trochę nieostry, stąd komentarz zamiast odpowiedzi. – SethWhite