Expliziter Durchgang
Ähnlich wie beim Verschachteln der Rückrufe beruht diese Technik auf Schließungen. Die Kette bleibt jedoch flach - anstatt nur das neueste Ergebnis zu übergeben, wird für jeden Schritt ein Statusobjekt übergeben. Diese Statusobjekte sammeln die Ergebnisse der vorherigen Aktionen und geben alle Werte, die später erneut benötigt werden, sowie das Ergebnis der aktuellen Aufgabe weiter.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Hier ist dieser kleine Pfeil b => [resultA, b]
die Funktion, die geschlossen resultA
wird und ein Array beider Ergebnisse an den nächsten Schritt übergibt. Womit die Syntax der Parameterdestrukturierung verwendet wird, um sie wieder in einzelne Variablen aufzuteilen.
Bevor die Destrukturierung mit ES6 verfügbar wurde, .spread()
wurde von vielen Versprechensbibliotheken ( Q , Bluebird , when ,…) eine raffinierte Hilfsmethode bereitgestellt . Es ist erforderlich, dass eine Funktion mit mehreren Parametern - einer für jedes Array-Element - als verwendet wird .spread(function(resultA, resultB) { …
.
Natürlich kann dieser hier benötigte Verschluss durch einige Hilfsfunktionen weiter vereinfacht werden, z
function addTo(x) {
// imagine complex `arguments` fiddling or anything that helps usability
// but you get the idea with this simple one:
return res => [x, res];
}
…
return promiseB(…).then(addTo(resultA));
Alternativ können Sie Promise.all
das Versprechen für das Array erstellen:
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
// as if passed to Promise.resolve()
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Und Sie können nicht nur Arrays verwenden, sondern auch beliebig komplexe Objekte. Zum Beispiel mit _.extend
oder Object.assign
in einer anderen Hilfsfunktion:
function augment(obj, name) {
return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(augment({resultA}, "resultB"));
}).then(function(obj) {
// more processing
return // something using both obj.resultA and obj.resultB
});
}
Während dieses Muster eine flache Kette garantiert und explizite Zustandsobjekte die Klarheit verbessern können, wird es für eine lange Kette mühsam. Besonders wenn Sie den Staat nur sporadisch brauchen, müssen Sie ihn dennoch durch jeden Schritt führen. Mit dieser festen Schnittstelle sind die einzelnen Rückrufe in der Kette ziemlich eng gekoppelt und können sich nicht ändern. Dadurch wird das Ausklammern einzelner Schritte erschwert, und Rückrufe können nicht direkt von anderen Modulen bereitgestellt werden. Sie müssen immer in Code gekoppelt werden, der sich um den Status kümmert. Abstrakte Helferfunktionen wie die oben genannten können den Schmerz ein wenig lindern, sind aber immer vorhanden.
javascript
, ist sie in einer anderen Sprache relevant. Ich benutze nur die Antwort "Break the Chain" in Java und jdeferred