Anhand des Titels der Frage "Versprechen nacheinander auflösen (dh nacheinander)?" Könnten wir verstehen, dass das OP mehr an der sequentiellen Behandlung von Versprechungen bei der Abwicklung als an sequentiellen Anrufen an sich interessiert ist .
Diese Antwort wird angeboten:
- um zu demonstrieren, dass sequentielle Aufrufe für die sequentielle Verarbeitung von Antworten nicht erforderlich sind.
- den Besuchern dieser Seite tragfähige alternative Muster aufzuzeigen - einschließlich des OP, wenn er über ein Jahr später noch interessiert ist.
- trotz der Behauptung des OP, dass er nicht gleichzeitig telefonieren möchte, was tatsächlich der Fall sein kann, aber ebenso eine Annahme sein kann, die auf dem Wunsch nach sequentieller Behandlung von Antworten beruht, wie der Titel impliziert.
Wenn gleichzeitige Anrufe wirklich nicht erwünscht sind, lesen Sie die Antwort von Benjamin Gruenbaum, in der sequentielle Anrufe (usw.) umfassend behandelt werden.
Wenn Sie jedoch (für eine verbesserte Leistung) an Mustern interessiert sind, die gleichzeitige Anrufe und anschließende sequentielle Bearbeitung von Antworten ermöglichen, lesen Sie bitte weiter.
Es ist verlockend zu glauben, dass Sie Promise.all(arr.map(fn)).then(fn)
(wie ich es schon oft getan habe) oder den ausgefallenen Zucker einer Promise lib (insbesondere den von Bluebird) verwenden müssen, aber (mit Anerkennung dieses Artikels ) ein arr.map(fn).reduce(fn)
Muster wird die Arbeit erledigen, mit den Vorteilen, dass es:
- funktioniert nur mit jeder Versprechen-Bibliothek - auch mit vorkonformen Versionen von jQuery
.then()
verwendet.
- bietet die Flexibilität, Fehler zu überspringen oder Fehler zu stoppen, je nachdem, was Sie mit einem einzeiligen Mod möchten.
Hier ist es geschrieben für 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.
});
};
Hinweis: Nur dieses eine Fragment Q()
ist spezifisch für Q. Für jQuery müssen Sie sicherstellen, dass readFile () ein jQuery-Versprechen zurückgibt. Mit A + libs werden ausländische Versprechen aufgenommen.
Der Schlüssel hier ist das sequence
Versprechen der Reduktion , das den Umgang mit den readFile
Versprechen, aber nicht deren Erstellung , in eine Reihenfolge bringt.
Und wenn Sie das einmal aufgenommen haben, ist es vielleicht etwas umwerfend, wenn Sie feststellen, dass die .map()
Bühne eigentlich nicht notwendig ist! Der gesamte Auftrag, parallele Anrufe plus serielle Bearbeitung in der richtigen Reihenfolge, kann reduce()
allein erledigt werden, plus dem zusätzlichen Vorteil einer weiteren Flexibilität für:
- Konvertieren Sie von parallelen asynchronen Aufrufen zu seriellen asynchronen Aufrufen, indem Sie einfach eine Zeile verschieben - möglicherweise nützlich während der Entwicklung.
Hier ist es Q
wieder.
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.
});
};
Das ist das Grundmuster. Wenn Sie dem Anrufer auch Daten (z. B. die Dateien oder eine Transformation davon) liefern möchten, benötigen Sie eine milde Variante.