Ich möchte diesen Punkt klarstellen, da die Dokumentation darüber nicht zu klar ist.
Q1: Ist die Promise.all(iterable)
Verarbeitung aller Versprechungen der Reihe nach oder parallel? Oder genauer gesagt, ist es das Äquivalent zu verketteten Versprechungen wie
p1.then(p2).then(p3).then(p4).then(p5)....
oder ist es eine andere Art von Algorithmus , bei dem alle p1
, p2
, p3
, p4
, p5
etc. zur gleichen Zeit (parallel) genannt werden und die Ergebnisse werden, sobald alle resolve (oder ein Spuck) zurück?
F2: Wenn Promise.all
parallel ausgeführt wird, gibt es eine bequeme Möglichkeit, eine iterierbare Sequenz sequentiell auszuführen?
Hinweis : Ich möchte nicht Q oder Bluebird verwenden, sondern alle nativen ES6-Spezifikationen.
javascript
node.js
promise
es6-promise
Yanick Rochon
quelle
quelle
Promise.all
sie parallel ausgeführt werden.node.js
undio.js
da ich es hier benutze. Also ja, die V8-Implementierung, wenn Sie so wollen.Promise.all
.new Promise(a).then(b); c();
a wird zuerst ausgeführt, dann c, dann b. Es ist nicht Promise.all, das diese Versprechen ausführt, sondern nur, wenn sie gelöst werden.Antworten:
Nein, Versprechen können nicht "ausgeführt" werden. Sie beginnen ihre Aufgabe, wenn sie erstellt werden - sie stellen nur die Ergebnisse dar - und Sie führen alles parallel aus, noch bevor Sie sie an übergeben
Promise.all
.Promise.all
wartet nur auf mehrere Versprechen. Es ist egal, in welcher Reihenfolge sie aufgelöst werden oder ob die Berechnungen parallel ausgeführt werden.Wenn Sie bereits Ihre Versprechen haben, können Sie nicht viel tun, aber
Promise.all([p1, p2, p3, …])
(was keine Vorstellung von Sequenz hat). Wenn Sie jedoch über eine Iteration asynchroner Funktionen verfügen, können Sie diese tatsächlich nacheinander ausführen. Grundsätzlich müssen Sie von bekommenzu
und die Lösung dafür ist
Array::reduce
:quelle
then
Sequenz - der Rückgabewert ist das Versprechen für das letztefn
Ergebnis, und Sie können andere Rückrufe daran ketten.fn1().then(p2).then(fn3).catch(…
? Es muss kein Funktionsausdruck verwendet werden.retValFromF1
wird das weitergegebenp2
, genau dasp2
macht es. Sicher, wenn Sie mehr tun möchten (zusätzliche Variablen übergeben, mehrere Funktionen aufrufen usw.), müssen Sie einen Funktionsausdruck verwenden, obwohl das Ändernp2
im Array einfacher wäreiterable
ist das[fn1, fn2, fn3, …]
ArrayParallel zu
Vorteile: Schneller. Alle Iterationen werden ausgeführt, auch wenn eine fehlschlägt.
Der Reihe nach
Vorteile: Variablen in der Schleife können von jeder Iteration gemeinsam genutzt werden. Benimmt sich wie normaler imperativer synchroner Code.
quelle
for (const item of items) await fetchItem(item);
await Promise.all(items.map(async item => { return await fetchItem(item).catch(e => e) }))
async
Funktion ein API-Aufruf ist und Sie den Server nicht als DDOS verwenden möchten. Sie haben eine bessere Kontrolle über die einzelnen Ergebnisse und Fehler, die bei der Ausführung auftreten. Noch besser können Sie entscheiden, welche Fehler fortgesetzt und welche Schleife unterbrochen werden soll.Die Antwort von Bergis hat mich mit Array.reduce auf den richtigen Weg gebracht.
Um jedoch tatsächlich zu erreichen, dass die Funktionen meine Versprechen zurückgeben, nacheinander ausgeführt zu werden, musste ich weitere Verschachtelungen hinzufügen.
Mein eigentlicher Anwendungsfall ist eine Reihe von Dateien, die ich aufgrund von nachgeschalteten Einschränkungen nacheinander übertragen muss ...
Hier ist, was ich am Ende hatte.
Wie aus den vorherigen Antworten hervorgeht, verwenden Sie:
Ich habe nicht auf den Abschluss der Übertragung gewartet, bevor ich eine weitere gestartet habe, und auch der Text "Alle übertragenen Dateien" wurde angezeigt, bevor die erste Dateiübertragung gestartet wurde.
Ich bin mir nicht sicher, was ich falsch gemacht habe, wollte aber mitteilen, was für mich funktioniert hat.
Bearbeiten: Seit ich diesen Beitrag geschrieben habe, verstehe ich jetzt, warum die erste Version nicht funktioniert hat. then () erwartet eine Funktion, die ein Versprechen zurückgibt. Sie sollten also den Funktionsnamen ohne Klammern übergeben! Jetzt möchte meine Funktion ein Argument, also muss ich mich in eine anonyme Funktion einfügen, die kein Argument akzeptiert!
quelle
nur um auf @ Bergis Antwort einzugehen (was sehr prägnant, aber schwierig zu verstehen ist;)
Dieser Code führt jedes Element im Array aus und fügt am Ende die nächste 'then-Kette' hinzu.
hoffe das macht Sinn.
quelle
Sie können eine iterierbare Funktion auch sequentiell mit einer asynchronen Funktion mithilfe einer rekursiven Funktion verarbeiten. Beispiel: Ein Array
a
, das mit asynchroner Funktion verarbeitet werden sollsomeAsyncFunction()
:quelle
array.prototype.reduce
ist in Bezug auf die Leistung viel besser als eine rekursive Funktionreduce
wo Sie die gesamtethen()
Kette in einem Schritt erstellen und dann ausführen müssen.Mit async wait kann eine Reihe von Versprechungen einfach nacheinander ausgeführt werden:
Hinweis: Wenn in der obigen Implementierung ein Versprechen abgelehnt wird, wird der Rest nicht ausgeführt. Wenn Sie möchten, dass alle Ihre Versprechen ausgeführt werden, wickeln Sie Ihr
await a[i]();
Inneres eintry catch
quelle
parallel
siehe dieses Beispiel
Durch Ausführen des Codes wird "CALLED" für alle sechs Versprechen getröstet, und wenn sie gelöst sind, werden alle 6 Antworten nach einer Zeitüberschreitung gleichzeitig getröstet
quelle
NodeJS führt Versprechen nicht parallel aus, sondern gleichzeitig, da es sich um eine Single-Threaded-Event-Loop-Architektur handelt. Es besteht die Möglichkeit, Dinge parallel auszuführen, indem ein neuer untergeordneter Prozess erstellt wird, um die Vorteile der Mehrkern-CPU zu nutzen.
Parallel Vs Concurent
In der Tat, was
Promise.all
stapeln Sie die Versprechensfunktion in der entsprechenden Warteschlange (siehe Ereignisschleifenarchitektur) sie gleichzeitig ausführen (Aufruf P1, P2, ...), dann auf jedes Ergebnis warten und dann Promise.all mit allen Versprechungen auflösen Ergebnisse. Promise.all schlägt beim ersten Versprechen fehl, das fehlschlägt, es sei denn, Sie haben die Ablehnung selbst verwaltet.Es gibt einen großen Unterschied zwischen parallel und gleichzeitig, der erste führt unterschiedliche Berechnungen in einem separaten Prozess genau zur gleichen Zeit aus und sie werden in diesem Rhythmus fortschreiten, während der andere die unterschiedlichen Berechnungen nacheinander ausführt, ohne auf den vorherigen zu warten Berechnung zu beenden und gleichzeitig fortzufahren, ohne voneinander abhängig zu sein.
Um Ihre Frage zu beantworten,
Promise.all
wird sie weder parallel noch sequentiell, sondern gleichzeitig ausgeführt.quelle
Bergis Antwort hat mir geholfen, den Aufruf synchron zu machen. Ich habe unten ein Beispiel hinzugefügt, in dem wir jede Funktion aufrufen, nachdem die vorherige Funktion aufgerufen wurde.
quelle
Sie können es mit for-Schleife tun.
Rückgabeversprechen der asynchronen Funktion
Wenn Sie folgenden Code schreiben, werden die Clients parallel erstellt
dann werden alle Clients parallel erstellt. Wenn Sie den Client jedoch nacheinander erstellen möchten, sollten Sie die for-Schleife verwenden
dann werden alle Clients nacheinander erstellt.
Happy Coding :)
quelle
async
/await
nur mit einem Transpiler oder mit anderen Motoren als Node verfügbar . Außerdem sollten Sie wirklich nicht mischenasync
mityield
. Während sie sich mit einem Transpiler gleich verhalten undco
wirklich sehr unterschiedlich sind und sich normalerweise nicht gegenseitig beeinflussen sollten. Sie sollten diese Einschränkungen auch erwähnen, da Ihre Antwort für unerfahrene Programmierer verwirrend ist.Ich habe für verwendet, um sequentielle Versprechen zu lösen. Ich bin mir nicht sicher, ob es hier hilft, aber das habe ich getan.
quelle
Dies könnte einen Teil Ihrer Frage beantworten.
Ja, Sie können ein Array von Versprechen zurückgebender Funktionen wie folgt verketten ... (dies übergibt das Ergebnis jeder Funktion an die nächste). Sie können es natürlich bearbeiten, um jeder Funktion dasselbe Argument (oder keine Argumente) zu übergeben.
quelle
Ich bin über diese Seite gestolpert, als ich versucht habe, ein Problem in NodeJS zu lösen: das Zusammensetzen von Dateiblöcken. Grundsätzlich gilt: Ich habe eine Reihe von Dateinamen. Ich muss alle diese Dateien in der richtigen Reihenfolge anhängen, um eine große Datei zu erstellen. Ich muss das asynchron machen.
Das 'fs'-Modul des Knotens bietet zwar appendFileSync, aber ich wollte den Server während dieses Vorgangs nicht blockieren. Ich wollte das Modul fs.promises verwenden und einen Weg finden, dieses Zeug miteinander zu verketten. Die Beispiele auf dieser Seite haben für mich nicht ganz funktioniert, da ich tatsächlich zwei Operationen benötigte: fsPromises.read () zum Einlesen des Dateiblocks und fsPromises.appendFile () zum Konzentrieren auf die Zieldatei. Wenn ich besser mit Javascript umgehen könnte, hätte ich vielleicht die vorherigen Antworten für mich arbeiten lassen können. ;-);
Ich bin darauf gestoßen ... https://css-tricks.com/why-using-reduce-to-sequential-resolve-promises-works/ ... und konnte eine funktionierende Lösung zusammen hacken.
TLDR:
Und hier ist ein Jasmin-Unit-Test dafür:
Ich hoffe es hilft jemandem.
quelle