Na podstawie tytułu pytania „Rozwiąż obietnice jeden po drugim (tj. W sekwencji)?”, Możemy zrozumieć, że OP jest bardziej zainteresowany sekwencyjną obsługą obietnic przy rozliczeniu niż sekwencyjnymi wezwaniami per se .
Ta odpowiedź jest oferowana:
- w celu wykazania, że sekwencyjne wywołania nie są konieczne do sekwencyjnego przetwarzania odpowiedzi.
- ujawnienia realnych alternatywnych wzorców odwiedzającym tę stronę - w tym PO, jeśli nadal będzie zainteresowany ponad rok później.
- pomimo twierdzenia OP, że nie chce on wykonywać połączeń jednocześnie, co może rzeczywiście mieć miejsce, ale równie dobrze może być założeniem opartym na chęci sekwencyjnego przetwarzania odpowiedzi, jak sugeruje tytuł.
Jeśli równoczesne połączenia nie są naprawdę pożądane, zapoznaj się z odpowiedzią Benjamina Gruenbauma, która obejmuje kompleksowo połączenia sekwencyjne (itp.).
Jeśli jednak jesteś zainteresowany (dla lepszej wydajności) wzorcami, które pozwalają na jednoczesne połączenia, a następnie sekwencyjną obsługę odpowiedzi, czytaj dalej.
Kuszące jest, aby pomyśleć, że musisz użyć Promise.all(arr.map(fn)).then(fn)
(jak już wiele razy) lub fantazyjnego cukru z Promise lib (zwłaszcza Bluebird), jednak (dzięki temu artykułowi ) arr.map(fn).reduce(fn)
wzór spełni swoje zadanie, z zaletami, które:
- działa tylko z każdą obietnicą lib - nawet z wcześniejszymi wersjami jQuery - tylko
.then()
używana jest .
- zapewnia elastyczność pomijania przekroczenia błędu lub zatrzymania po błędzie, w zależności od tego, co chcesz za pomocą modu z jedną linią.
Oto jest napisane dla Q
.
var readFiles = function(files) {
return files.map(readFile) //Make calls in parallel.
.reduce(function(sequence, filePromise) {
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//skip-over-error. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
Uwaga: tylko ten jeden fragment, Q()
jest specyficzny dla Q. W przypadku jQuery musisz upewnić się, że readFile () zwraca obietnicę jQuery. Z bibliotekami A + obietnice zagraniczne zostaną zasymilowane.
Kluczem tutaj jest sequence
obietnica redukcji , która porządkuje postępowanie z readFile
obietnicami, ale nie ich tworzenie.
A kiedy już to zrozumiesz, może być nieco oszałamiające, gdy zdasz sobie sprawę, że .map()
scena nie jest tak naprawdę konieczna! Całe zadanie, połączenia równoległe i obsługa szeregowa w prawidłowej kolejności, można wykonać reduce()
samodzielnie, a także dodatkową zaletą dodatkowej elastyczności w zakresie:
- konwertuj z równoległych wywołań asynchronicznych na szeregowe wywołania asynchroniczne, po prostu przesuwając jedną linię - potencjalnie przydatne podczas programowania.
Oto Q
znowu.
var readFiles = function(files) {
return files.reduce(function(sequence, f) {
var filePromise = readFile(f);//Make calls in parallel. To call sequentially, move this line down one.
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//Skip over any errors. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
To jest podstawowy wzór. Jeśli chcesz również dostarczyć dane (np. Pliki lub ich transformację) do dzwoniącego, potrzebujesz łagodnego wariantu.