Gewusst wie: synchronisieren von einer Sequenz von verspricht?
Ich habe ein array von promise-Objekte, die gelöst werden müssen in der gleichen Reihenfolge, in der Sie aufgeführt sind, in das array, d.h. wir können nicht versuchen, der Lösung ein element, bis das Vorherige gelöst wurde (als Methode Promise.all([...])
tut).
Und wenn ein element abgelehnt wird, muss ich die Kette ablehnen, auf einmal, ohne zu versuchen, beheben Sie das folgende element.
Wie kann ich diese umsetzen, oder gibt es eine vorhandene Implementierung für solche sequence
Muster?
function sequence(arr) {
return new Promise(function (resolve, reject) {
//try resolving all elements in 'arr',
//but strictly one after another;
});
}
BEARBEITEN
Den ersten Antworten vorschlagen, wir können nur sequence
Ergebnisse der array-Elemente, nicht deren Ausführung, weil es vorgegeben ist Beispiel.
Dann aber so erzeugen Sie ein array von Verheißungen in einer Weise zu vermeiden, frühe Ausführung?
Hier ist ein modifiziertes Beispiel:
function sequence(nextPromise) {
//while nextPromise() creates and returns another promise,
//continue resolving it;
}
Ich würde nicht wollen, um es in eine separate Frage, weil ich glaube, es ist Teil des gleichen Problems.
LÖSUNG
Einige Antworten unten und die Diskussionen, die folgten, ging ein wenig in die Irre, aber die letztendliche Lösung, die genau das Tat, was ich suchte war die Implementierung innerhalb spex Bibliothek als Methode Sequenz. Die Methode zum iterieren durch eine Sequenz von dynamischer Länge, und erstellen Sie verspricht, wie es die business-Logik der Anwendung.
Später auf ich verwandelte es in eine gemeinsame Bibliothek für jedermann zu benutzen.
.each
und .reduce
tun, in die docs - Sie brauchen, um an Ihnen einen promire-die Rückkehr-Funktion (was auch immer gibt, die Versprechungen, die Sie in Ihrem sequence
wie für die Verkettung Versprechen, die Sie tun können promise.then(promiseReturningFn)
Ich würde vorschlagen, erweitern Ihre Antwort auf die Frage, wie eine solche Reihe von Versprechen erzeugt werden sollen, um zu vermeiden, frühe Ausführung. Dies ist ein Thema, das verdient eine ganz neue Frage, aber es ist Teil des gleichen Problems.
Wenn Sie ein promise-Objekt, bedeutet es, dass die Versprechen, hat bereits alles, was es braucht, um seine Arbeit zu tun, und alles, was Sie tun müssen, ist warten, es zu rufen Sie zurück (via Rückruf). Wenn Sie bereits ein Versprechen, und irgendwie müssen Sie jetzt tun, die Synchronisierung der Arbeit, die Art, wie Sie arbeiten, mit dem Versprechen ist gebrochen. Sie müssen gehen Sie zurück und betrachten Sie die phase, wo Sie Ihre Versprechen erstellt werden und überarbeiten Sie, dass die Verkettung verspricht zusammen wenn es sein muss.
Ich glaube, ich habe genau das, und habe meine Lösung vor, die Sie geschrieben dein Kommentar 🙂
Eine einfache und nützliche Art und Weise: synch verspricht
InformationsquelleAutor vitaly-t | 2015-04-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier sind einige einfache Beispiele dafür, wie Sie die Sequenz durch eine Reihe Ausführung jeder async-Betrieb Seriell (eins nach dem anderen).
Nehmen wir an, Sie haben ein array von Elementen:
Und Sie wollen zu tragen eine bestimmte asynchrone operation auf jedes Element im array, jeweils abwechselnd, so dass die nächste Aktion nicht zu starten, bis die Vorherige fertig ist.
Und, nehmen wir an, Sie haben ein Versprechen der Rückkehr-Funktion für die Bearbeitung eines der Elemente im array
fn(item)
:Manuelle Iteration
Dann können Sie etwas wie das hier tun:
Manuelle Iteration Rückkehr Versprechen
Wenn Sie wollte ein Versprechen zurück von
processArray()
so würden Sie wissen, wenn es gemacht wurde, könnte man hinzufügen, diese es:Hinweis: dies wird verhindern, dass die Kette auf der ersten Ablehnung und der pass, der Grund zurück an den processArray zurückgegeben Versprechen.
Iteration mit .reduce()
Wenn Sie das tun wollten mehr von der Arbeit mit dem Versprechen, Sie könnten die Kette der Verheißungen:
Hinweis: dies wird verhindern, dass die Kette auf die erste Ablehnung, und übergeben Sie deshalb zurück zu der Verheißung zurück von
processArray()
.Erfolg Szenario, das Versprechen zurück von
processArray()
gelöst werden mit dem letzten aufgelöst Wert Ihrerfn
Rückruf. Wenn Sie wollten, zu sammeln eine Liste der Ergebnisse und die Entschlossenheit, mit Sie sammeln konnte, die Ergebnisse einer Schließung array vonfn
und weiter zurück, das array wird jedes mal, so dass die endgültige Behebung wäre ein array der Ergebnisse.Iteration mit .reduce (), die Löst sich Mit der Array -
Und da scheint es nun offensichtlich, dass Sie wollen, dass die endgültige Versprechen zu Folge werden eine Reihe von Daten (in der Reihenfolge), hier ist eine überarbeitung der bisherigen Lösung, die produziert:
Arbeiten demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
Sowie eine funktionierende demo, die zeigt, dass eine Ablehnung: http://jsfiddle.net/jfriend00/p0ffbpoc/
Iteration mit .reduce (), die Löst sich Mit der Array mit Verzögerung
Und, wenn Sie möchten, legen Sie eine kleine Verzögerung zwischen Vorgängen:
Iteration mit Bluebird Versprechen Bibliothek
Bluebird Versprechen-Bibliothek hat eine Menge von Parallelität controlling-Funktionen direkt in Sie integriert. Zum Beispiel, um die Sequenz iteration durch ein array verwenden, können Sie
Promise.mapSeries()
.Oder legen Sie eine Verzögerung zwischen Iterationen:
Mit ES7 async/await
Wenn Sie die Kodierung in einer Umgebung, unterstützt async/await, können Sie auch einfach einen regulären
for
Schleife und dannawait
ein Versprechen in der Schleife und es wird dazu führen, diefor
Schleife zu unterbrechen, bis ein Versprechen behoben ist, bevor Sie fortfahren. Dies wird effektiv die Reihenfolge Ihrer asynchronen Operationen, so dass die nächste nicht erst beginnen, wenn die Vorherige erledigt ist.FYI, ich glaube, meine
processArray()
- Funktion ist hier sehr ähnlichVersprechen.map()
in der Bluebird Versprechen-Bibliothek, die nimmt ein array und ein Versprechen Produktionsfunktion und gibt ein Versprechen, dass löst sich mit einem array gelöst, Ergebnisse.@vitaly-t - Hier einige detailliertere Kommentare auf Ihrem Ansatz. Sie sind herzlich eingeladen zu den gewünschten code scheint am besten zu Ihnen. Als ich begann, mit Versprechungen, die ich eher verwenden Sie verspricht, nur für die einfachsten Dinge, die Sie haben und schreiben viele der Logik selbst, wenn eine erweiterte Nutzung der verspricht noch viel mehr von ihm für mich. Sie verwenden nur das, was Sie sind völlig bequem mit und darüber hinaus, Sie würde lieber sehen, Ihre eigenen Codes, die Sie innig kennen. Das ist wohl die menschliche Natur.
Werde ich vorschlagen, dass ich, als ich Verstand mehr und mehr von dem, was verspricht für mich tun kann, die ich jetzt gerne schreiben Sie code, der verwendet, mehr über die erweiterten features von Verheißungen und scheint es ganz natürlich zu mir und ich fühle mich wie ich bin, aufbauend auf erprobten Infrastruktur, hat viele nützliche Funktionen. Ich würde Sie nur bitten, halten Sie Ihren Geist offen, wie Sie mehr und mehr potenziell gehen, die Richtung. Es ist meine Meinung, dass es eine nützliche und produktive Richtung zu migrieren, da sich Ihr Verständnis verbessert.
Hier sind einige spezifische Punkte des feedback auf Ihr Konzept:
Erstellen Sie verspricht an sieben stellen
Als Kontrast in Stilen, mein code hat nur zwei Orte, wo ich explizit erstellen Sie eine neue Versprechen - einmal in der factory-Funktion und einmal zum initialisieren der
.reduce()
Schleife. Überall sonst bin ich nur auf die Versprechen bereits erstellt durch die Verkettung von Ihnen oder zurückgeben von Werten, die in Ihnen oder einfach wieder direkt von Ihnen. Dein code hat sieben einzigartige Orte, an denen Sie erstellen ein Versprechen. Jetzt, gute Codierung ist nicht ein Wettbewerb, um zu sehen, wie wenige Orte, die Sie erstellen können, ein Versprechen, aber das könnte auf den Unterschied in den nutzen der Verheißungen, die bereits angelegt sind gegen das testen von Bedingungen und die Schaffung von neuen Versprechungen.Werfen-Sicherheit ist ein sehr nützliches feature
Versprechen zu werfen-sicher ist. Das bedeutet, dass eine Ausnahme geworfen, die innerhalb ein Versprechen handler wird automatisch abzulehnen, die das Versprechen. Wenn Sie wollen einfach nur die Ausnahme zu einer Ablehnung, dann ist dies ein sehr nützliches feature zu nutzen. In der Tat, Sie werden feststellen, dass nur das werfen selbst ist eine nützliche Methode, um ablehnen, die aus einer handler erstellen ohne noch ein weiteres Versprechen.
Viele
Promise.resolve()
oderPromise.reject()
ist wohl eine Möglichkeit für die VereinfachungWenn Sie sehen, dass code, der mit viel
Promise.resolve()
oderPromise.reject()
Aussagen, dann gibt es wahrscheinlich Möglichkeiten zu nutzen, die vorhandenen verspricht besser, anstatt all diese neuen Versprechungen.Stimmen, um ein Versprechen
Wenn Sie nicht wissen, ob etwas zurückgegeben, ein Versprechen, dann können Sie werfen Sie es einem Versprechen. Das Versprechen-Bibliothek wird dann Mach es selbst prüft, ob es ein Versprechen ist oder nicht und auch ob es die Art von Versprechen, das entspricht dem Versprechen, die Bibliothek, die Sie verwenden, und wenn nicht, wickeln Sie es in einem. Dies kann sparen Sie umschreiben eine Menge von dieser Logik selbst.
Vertrag Zurück ein Versprechen
In vielen Fällen sind diese Tage, es ist ganz sinnvoll einen Vertrag für eine Funktion, die können Sie etwas tun, asynchrone zurückzukehren ein Versprechen. Wenn Sie die Funktion nur etwas tun will, synchron, dann kann es einfach nur wieder gelöst Versprechen. Sie scheinen zu fühlen, wie das ist belastend, aber es ist definitiv die Art und Weise der wind weht, und ich bereits eine Menge Quellcode schreiben muss und es fühlt sich sehr natürlich, wenn Sie machen Sie sich vertraut mit dem Versprechen. Es abstrahiert entfernt, ob die operation sync oder async und Aufrufer muss nicht wissen, oder etwas besonderes tun oder so. Dies ist eine schöne Nutzung verspricht.
Die factory-Funktion geschrieben werden können, erstellen Sie ein Versprechen nur
Die factory-Funktion geschrieben werden können, erstellen Sie ein Versprechen nur und dann beheben oder ablehnen. Dieser Stil macht es auch werfen sicher, so dass keine Ausnahme Auftritt in der factory-Funktion wird automatisch eine Ablehnung. Es macht auch den Vertrag immer wieder ein Versprechen automatisch.
Während ich erkenne, dass dieser factory-Funktion ist ein Platzhalter-Funktion (es muss nicht einmal etwas tun, async), hoffentlich können Sie sehen, der Stil, halten es:
Wenn alle diese Operationen waren, async, dann könnten Sie einfach nur wieder Ihre eigenen Verheißungen, die würde automatisch die Kette zu einem zentralen Versprechen wie dieses:
Mit einem ablehnen handler nur
return promise.reject(reason)
ist nicht erforderlichWenn Sie diese Körper-code:
Ablehnen-handler ist nicht jede Zugabe Wert. Stattdessen können Sie genau dies tun:
Sind Sie bereits und gibt das Ergebnis zurück von
obj.then()
. Wenn entwederobj
ablehnt oder wenn irgendetwas angekettet anobj
oder zurückgegeben wird, dann.then()
handler ablehnt, dannobj
ablehnen wird. So müssen Sie nicht erstellen Sie ein neues Versprechen mit den ablehnen. Die einfacheren code ohne die reject-hf macht das gleiche mit weniger code.Hier ist eine version in der Allgemeinen Architektur Ihrer code, der versucht zu integrieren, und die meisten dieser Ideen:
Arbeiten demo: http://jsfiddle.net/jfriend00/h3zaw8u8/
Einige Kommentare zu dieser Umsetzung:
Promise.resolve(factory(idx))
im wesentlichen wirft das Ergebnisfactory(idx)
ein Versprechen. Wenn es nur einen Wert, dann wird es gelöst, das Versprechen, dass der Rückgabewert als die Entschlossenheit Wert. Wenn es schon ein Versprechen, dann ist es eben Ketten zu diesem Versprechen. Also, es ersetzt alle Ihre Typ-Prüfung-code auf der Rückgabewert derfactory()
Funktion.Die factory-Funktion signalisiert, dass es gemacht wird-durch Rücksendung entweder
null
oder ein Versprechen, der ' s gelöst Wert endet alsnull
. Die oben Besetzung ordnet diese beiden Bedingungen die gleiche resultierende code.Die factory-Funktion Ausnahmen erfasst automatisch und verwandelt Sie in lehnt die werden dann automatisch abgewickelt, indem die
sequence()
Funktion. Dies ist ein wesentlicher Vorteil, dass verspricht eine Menge tun, Ihre Fehler-handling wenn Sie nur wollen, zu Abbrechen, Verarbeitung und füttern die Fehler zurück auf die erste Ausnahme oder Ablehnung.Die factory-Funktion in dieser Implementierung kann wieder entweder ein Versprechen oder einen statischen Wert (für eine synchrone operation) und es wird funktionieren just fine (pro Ihr design-Anforderung).
Getestet hab ich es mit einer geworfenen Ausnahme an die Verheißung, die callback in der factory-Funktion und es ist ja nur abzulehnen und zu propagieren, dass die Ausnahme zur Ablehnung der Sequenz Versprechen, mit der Ausnahme als der Grund.
Dieser verwendet eine ähnliche Methode, wie Sie (auf den Zweck, zu versuchen, bleiben Sie mit Ihrer Allgemeinen Architektur) für die Verkettung mehrerer Anrufe zu
loop()
.Ich versuche nur, um neue Ideen einbringen (das ist wie StackOverflow funktioniert). Sie haben nicht angenommen keine Antwort, aber ich dachte, dass Sie speziell waren immer noch offen für Ideen. Alle meine code-Beispiele Anschlag auf die erste Ablehnung. Mein 2. und 3. Optionen auch übertragen, den Ablehnungsgrund zurück, um die zurückgegebenen Versprechen. Und, schließlich, ich weiß nicht, was "lösen das endgültige Ergebnis der operation" bedeutet. Ich sehe nicht ein Beispiel in Ihrer Antwort erklärt, so wusste ich nicht, das war eine Anforderung oder verstehen, was es ist. Erklären Sie bitte, dass die Anforderung und die kann ich anpassen.
Der einzige Grund, warum ich nicht akzeptieren, meine Antwort - StackOverflow nicht lassen Sie es für 3 Tage nach dem post, die nicht für mich Sinn machen, aber hier ist es, und ich kann es immer noch nicht, muss warten...
OK, einen letzten Punkt feedback. Ich habe Hinzugefügt, um das Ende meiner Antwort, die einige sehr spezifische Punkte des feedback auf Ihre Umsetzung und anschließend eine neue Implementierung, die verwendet Ihre Allgemeine Struktur, sondern versucht zu integrieren, und diejenigen Punkte von feedback. Sie sind offenbar frei, zu verwenden, was code, den Sie am besten gefällt, aber ich dachte, es lohnt sich zu erklären, einige der Logik hinter einer anderen Umsetzung. Ich hoffe, Sie nehmen es nur als einen Gedanken/lernen wollen. Nichts mehr als das bedeutet es.
Sie sind der MANN! Wurden für so etwas suchen, für das Alter. Klare und ausführliche Antworten. Danke!
InformationsquelleAutor jfriend00
Verspricht darstellen Werte der Operationen und nicht die Vorgänge selbst. Die Operationen sind bereits begonnen so können Sie nicht machen Sie warten, für einen anderen.
Stattdessen können Sie synchronisieren - Funktionen, die Rückkehr verspricht aufrufen, damit Sie in die (durch eine Schleife mit Versprechen, die die Verkettung zum Beispiel), oder mit dem
.each
Methode in bluebird.Können Sie ein Beispiel dafür?
InformationsquelleAutor Benjamin Gruenbaum
Kann man nicht einfach X-asynchrone Operationen und dann will, dass Sie aufgelöst werden in eine Bestellung.
Den richtigen Weg, so etwas zu tun, ist die Ausführung des neuen async-Betrieb nur nach der einen, bevor Sie aufgelöst wurde:
Bearbeiten
Scheint, wie Sie wollen, warten Sie, bis alle Versprechungen und rufen Sie dann die Rückrufe, die in einer bestimmten Reihenfolge. So etwas wie dieses:
dann:
Die Probleme, die auftreten können, mit diesem ist, wenn eine oder mehrere Versprechungen scheitern.
Ich verstehe die beiden Antworten, die ich bekam, und daher aktualisiert meine Frage ein wenig, so können wir näher an eine richtige Lösung.
Danke..ich bin nicht hier, weil der up Stimmen. Ich bevorzuge die pay-it-forward-Ansatz!
InformationsquelleAutor Amir Popovich
Obwohl ganz dicht, hier ist eine andere Lösung, das wird Durchlaufen, ein Versprechen-Rückkehr-Funktion über ein array von Werten und beheben mit einer Reihe von Ergebnissen:
Verwendung:
Beachten Sie, dass, weil wir eine Verringerung von einem Versprechen auf den nächsten, jedes Element bearbeitet wird in Serie.
Es ist funktionell äquivalent zu der "Iteration mit .reduce (), die Löst sich Mit der Array" - Lösung von @jfriend00 aber ein bisschen ordentlicher.
InformationsquelleAutor Molomby
Nehme ich zwei Ansätze zum Umgang mit dieser Frage:
InformationsquelleAutor Iman Bahrampour
Meiner Meinung nach, sollten Sie mit Hilfe einer for-Schleife(die ja erst mal würde ich empfehlen, eine for-Schleife). Der Grund dafür ist, dass, wenn Sie mithilfe einer for-Schleife ermöglicht es Ihnen, um
await
auf jede der Iterationen der Schleife, wo mitreduce
,map
oderforEach
mit alle deine Versprechen Iterationen gleichzeitig. Die von den Klängen der es nicht ist, was Sie wollen, Sie wollen, dass jedes Versprechen, zu warten, bis der Vorherige Versprechen gelöst hat. So zu tun, dies tun Sie etwas wie das folgende.Und offensichtlich, wenn Sie wollten wirklich extrem, Sie könnten etwas tun, wie diese:
Dies ist so viel besser lesbar als die anderen Beispiele, es ist viel weniger code, reduziert die Anzahl der Zeilen benötigt für diese Funktionalität, folgt einem mehr funktionale Programmierung Weg, Dinge zu tun und ist mit ES7 zu seinem vollen potential!!!!
Auch je nach Ihrer Einrichtung oder, wenn Sie dies Lesen, müssen Sie die
plugin-proposal-async-generator-functions
polyfill oder Sie möglicherweise die folgende Fehlermeldung angezeigt@babel/plugin-proposal-async-generator-functions (https://git.io/vb4yp) to the 'plugins' section of your Babel config to enable transformation.
InformationsquelleAutor Brady Edgar