Ich bin kürzlich ein paar Mal in eine bestimmte Situation geraten, die ich nicht richtig lösen konnte. Nehmen Sie den folgenden Code an:
somethingAsync()
.then( afterSomething )
.then( afterSomethingElse )
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
}
Jetzt könnte eine Situation entstehen, in der ich Zugang zu amazingData
in haben möchte afterSomethingElse
.
Eine naheliegende Lösung wäre, ein Array oder einen Hash von zurückzugeben afterSomething
, da Sie nur einen Wert von einer Funktion zurückgeben können. Aber ich frage mich, ob es eine Möglichkeit gibt afterSomethingElse
, zwei Parameter zu akzeptieren und sie ebenfalls aufzurufen, da dies viel einfacher zu dokumentieren und zu verstehen scheint.
Ich wundere mich nur über diese Möglichkeit, da es Q.spread
etwas gibt , das etwas Ähnliches tut, was ich will.
javascript
promise
q
Der Hochstapler
quelle
quelle
Antworten:
Sie können ein Versprechen nicht mit mehreren Eigenschaften auflösen, genauso wie Sie nicht mehrere Werte von einer Funktion zurückgeben können . Ein Versprechen stellt konzeptionell einen Wert im Laufe der Zeit dar. Während Sie also zusammengesetzte Werte darstellen können, können Sie nicht mehrere Werte in ein Versprechen einfügen.
Ein Versprechen wird von Natur aus mit einem einzigen Wert aufgelöst. Dies ist Teil der Funktionsweise von Q, der Funktionsweise der Versprechen / A + -Spezifikation und der Funktionsweise der Abstraktion .
Das Beste, was Sie bekommen können, ist die Verwendung
Q.spread
und Rückgabe von Arrays oder die Verwendung der ES6-Destrukturierung, wenn dies unterstützt wird oder Sie bereit sind, ein Transpilationswerkzeug wie BabelJS zu verwenden.Bezüglich der Weitergabe des Kontexts an eine Versprechenskette verweisen wir bitte auf Bergis exzellenten Kanon .
quelle
.spread()
Bluebird in dieser verwandten Antwort angezeigt wirdPromise.all([a, b, c]).then(function(x, y, z) {...})
funktioniert in allen modernen Javascript-Engines korrekt, wobei x, y und z die aufgelösten Werte von a, b und c auswerten. Es ist also genauer zu sagen, dass die Sprache es Ihnen nicht einfach (oder vernünftig) macht, dies aus dem Benutzercode heraus zu tun (da Sie ein Versprechen direkt aus einer then-Klausel zurückgeben können, können Sie Ihre Werte in Versprechen einschließen und diese dann mit Versprechen einschließen .all (), um das gewünschte Verhalten zu erhalten, wenn auch auf verschlungene Weise).Promise.all
erfüllt mit einem Array . InPromise.all([a,b]).then((a, b) =>
b
istundefined
. Deshalb müssen Sie tun,.then(([a, b]) =>
was eine destrukturierende Aufgabe istSie können nur einen Wert übergeben, es kann sich jedoch auch um ein Array mit mehreren Werten handeln:
Auf der anderen Seite können Sie den Destrukturierungsausdruck für ES2015 verwenden, um die einzelnen Werte abzurufen.
beide Versprechen nennen, verketten:
quelle
function step2([server, data]) { …
- Auf diese Weise vermeiden Sie auch die Zuordnung zu impliziten Globalen. Und Sie sollten wirklichreturn
oderPromise.resolve
nicht dennew Promise
Konstruktor in Ihren Beispielen verwenden.Sie können ein Objekt zurückgeben, das beide Werte enthält - daran ist nichts auszusetzen.
Eine andere Strategie besteht darin , den Wert über Schließungen zu erhalten, anstatt ihn weiterzugeben :
Vollständige statt teilweise inlinierte Form (äquivalent, wohl konsistenter):
quelle
then
anderes zurückzugebenthen
? Es ist kein Anti-Muster ?Zwei Dinge, die Sie tun können, ein Objekt zurückzugeben
Verwenden Sie das Zielfernrohr!
quelle
Hier ist, wie ich denke, dass Sie tun sollten.
die Kette teilen
Da beide Funktionen erstaunlichDaten verwenden , ist es sinnvoll, sie in einer dedizierten Funktion zu haben. Normalerweise mache ich das jedes Mal, wenn ich einige Daten wiederverwenden möchte, sodass sie immer als Funktionsargument vorhanden sind.
Da in Ihrem Beispiel Code ausgeführt wird, wird angenommen, dass alles in einer Funktion deklariert ist. Ich werde es toto () nennen . Dann haben wir eine weitere Funktion, die sowohl afterSomething () als auch afterSomethingElse () ausführt .
Sie werden auch feststellen, dass ich eine Rückgabeerklärung hinzugefügt habe , da dies normalerweise der richtige Weg für Versprechen ist. Sie geben immer ein Versprechen zurück, damit wir bei Bedarf weiter verketten können. Hier wird etwas Async () erstaunliche Daten erzeugen und es wird überall in der neuen Funktion verfügbar sein.
Wie diese neue Funktion aussehen wird, hängt normalerweise davon ab, ob processAsync () auch asynchron ist .
processAsync nicht asynchron
Kein Grund, Dinge zu komplizieren, wenn processAsync () nicht asynchron ist. Ein alter guter sequentieller Code würde es schaffen.
Beachten Sie, dass es keine Rolle spielt, ob afterSomethingElse () etwas Asynchrones tut oder nicht. In diesem Fall wird ein Versprechen zurückgegeben und die Kette kann fortgesetzt werden. Ist dies nicht der Fall, wird der Ergebniswert zurückgegeben. Da die Funktion jedoch von then () aufgerufen wird , wird der Wert ohnehin in ein Versprechen eingeschlossen (zumindest in rohem Javascript).
processAsync asynchron
Wenn processAsync () asynchron ist, sieht der Code etwas anders aus. Hier betrachten wir, dass afterSomething () und afterSomethingElse () nirgendwo anders wiederverwendet werden.
Gleich wie zuvor für afterSomethingElse () . Es kann asynchron sein oder nicht. Ein Versprechen wird zurückgegeben oder ein Wert in ein gelöstes Versprechen eingewickelt.
Ihr Codierungsstil kommt dem, was ich mache, ziemlich nahe, deshalb habe ich auch nach 2 Jahren geantwortet. Ich bin kein großer Fan von anonymen Funktionen überall. Ich finde es schwer zu lesen. Auch wenn es in der Gemeinde durchaus üblich ist. Es ist so, als hätten wir die Rückruf-Hölle durch ein Versprechen-Fegefeuer ersetzt .
Ich halte auch gerne den Namen der Funktionen in der dann kurz. Sie werden sowieso nur lokal definiert. Und die meiste Zeit rufen sie eine andere Funktion auf, die an anderer Stelle definiert ist - also wiederverwendbar -, um die Arbeit zu erledigen. Ich mache das sogar für Funktionen mit nur 1 Parameter, so dass ich die Funktion nicht ein- und ausschalten muss, wenn ich der Funktionssignatur einen Parameter hinzufüge / entferne.
Beispiel essen
Hier ist ein Beispiel:
Konzentrieren Sie sich nicht zu sehr auf Promise.resolve () . Es ist nur ein schneller Weg, um ein gelöstes Versprechen zu erstellen. Was ich damit erreichen möchte, ist, den gesamten Code, den ich ausführe, an einem einzigen Ort zu haben - direkt unter den Thens . Alle anderen Funktionen mit einem aussagekräftigeren Namen können wiederverwendet werden.
Der Nachteil dieser Technik ist, dass sie viele Funktionen definiert. Aber ich fürchte, es ist ein notwendiger Schmerz, um zu vermeiden, überall anonyme Funktionen zu haben. Und was ist das Risiko überhaupt: ein Stapelüberlauf? (Scherz!)
Die Verwendung von Arrays oder Objekten, wie in anderen Antworten definiert, würde ebenfalls funktionieren. Dies ist in gewisser Weise die Antwort von Kevin Reid .
Sie können auch bind () oder Promise.all () verwenden . Beachten Sie, dass Sie weiterhin Ihren Code teilen müssen.
mit bind
Wenn Sie Ihre Funktionen wiederverwendbar halten wollen , aber nicht wirklich brauchen , zu halten , was im Inneren der ist dann sehr kurz, können Sie bind () .
Um es einfach zu halten, wird bind () der Liste der Argumente (mit Ausnahme der ersten) beim Aufruf vor die Funktion stellen.
mit Promise.all
In Ihrem Beitrag haben Sie die Verwendung von verbreiten () erwähnt . Ich habe das von Ihnen verwendete Framework nie verwendet, aber hier ist, wie Sie es verwenden können sollten.
Einige glauben, dass Promise.all () die Lösung für alle Probleme ist, daher sollte es wohl erwähnt werden.
Sie können Daten an Promise.all () übergeben - beachten Sie das Vorhandensein des Arrays - solange Versprechen vorliegen. Stellen Sie jedoch sicher, dass keines der Versprechen fehlschlägt, da sonst die Verarbeitung beendet wird.
Und anstatt neue Variablen aus dem Argument args zu definieren , sollten Sie in der Lage sein , pread () anstelle von then () für alle Arten von großartiger Arbeit zu verwenden.
quelle
Erstellen Sie einfach ein Objekt und extrahieren Sie Argumente aus diesem Objekt.
Ziehen Sie Argumente aus versprechenResolution.
quelle
Was auch immer Sie von einem Versprechen zurückgeben, wird in ein Versprechen eingewickelt, das in der nächsten
.then()
Phase ausgepackt werden soll .Es wird interessant, wenn Sie ein oder mehrere Versprechen neben einem oder mehreren synchronen Werten zurückgeben müssen, wie z.
In diesen Fällen wäre es wichtig, zu verwenden und Versprechen in der nächsten Phase ausgepackt
Promise.all()
zu bekommen, wie zp1
p2
.then()
quelle
Sie können Observable aktivieren , das durch Rxjs dargestellt wird , und mehr als einen Wert zurückgeben.
quelle
Sie können ein Array bereitstellen und eine Funktion in Ihrer Auflösung ausführen
quelle