Mit async/await-mit einer forEach-Schleife
Gibt es irgendwelche Probleme bei der Verwendung async/await
im forEach
- Schleife? Ich versuche, eine Schleife durch ein array von Dateien und await
auf den Inhalt jeder Datei.
import fs from 'fs-promise'
async function printFiles () {
const files = await getFilePaths() //Assume this works fine
files.forEach(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
})
}
printFiles()
Dieser code funktioniert, aber könnte etwas schief gehen mit diesem? Ich hatte mir mal jemand sagen, dass man nicht verwenden sollte async/await
in eine höhere Ordnung, die Funktion so aus ich wollte nur Fragen, ob es ein Problem mit diesem.
InformationsquelleAutor saadq | 2016-06-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sicher, dass der code funktioniert, aber ich bin mir ziemlich sicher, dass es nicht das tun, was Sie erwarten, es zu tun. Es ist einfach feuert mehrere asynchrone Aufrufe, aber die
printFiles
Funktion nicht sofort zurück nach.Wenn Sie möchten, Lesen Sie die Dateien in der Reihenfolge, Sie nicht verwenden
forEach
in der Tat. Nur mit einem modernenfor … of
Schleife statt, in denenawait
funktioniert wie erwartet:Wenn Sie wollen, um die Dateien Lesen, die in parallel, Sie nicht verwenden
forEach
in der Tat. Jeder derasync
callback-Funktion ruft nicht zurück ein Versprechen, aber Sie werfen Sie Weg, anstatt auf Sie warten. Verwenden Sie einfachmap
statt, und Sie können erwarten, die das array von Versprechungen, die Sie erhalten mitPromise.all
:for ... of ...
Arbeit?ok, ich weiß warum... Mit Babel zu verwandeln
async
/await
an-generator-Funktion und den EinsatzforEach
bedeutet, dass jede iteration hat einen einzelnen generator-Funktion, die hat nichts zu tun mit den anderen. so werden Sie unabhängig und hat keinen Zusammenhang mitnext()
mit anderen. Eigentlich eine einfachefor()
loop funktioniert auch, weil die Iterationen sind auch in einem einzelnen generator-Funktion.In kurz, denn es wurde entwickelt, um zu arbeiten 🙂
await
unterbricht den aktuellen Funktion - Bewertung, einschließlich aller Kontroll-Strukturen. Ja, es ist ganz ähnlich wie die Generatoren in dieser Hinsicht (das ist, warum Sie verwendet werden, um polyfill async/await).Nicht wirklich, ein
async
Funktion ist sehr Verschieden von einemPromise
Testamentsvollstrecker Rückruf, aber ja diemap
callback gibt ein Versprechen, in beiden Fällen.Wenn Sie kommen, um zu erfahren, über JS verspricht, sondern stattdessen eine halbe Stunde übersetzen aus dem lateinischen. Hoffe, du bist stolz auf @Bergi 😉
InformationsquelleAutor Bergi
Mit ES2018, Sie sind in der Lage, erheblich vereinfachen alle der oben genannten Antworten zu:
Siehe spec: https://github.com/tc39/proposal-async-iteration
2018-09-10: Diese Antwort wurde immer eine Menge Aufmerksamkeit vor kurzem, siehe Axel Rauschmayer blog-post für weitere Informationen über die asynchrone iteration: http://2ality.com/2016/10/asynchronous-iteration.html
Wo ist
file
im code definiert?Sollte es nicht Inhalt, wird anstelle der Datei in der "iterator"
Warum sind die Menschen upvoting diese Antwort? Nehmen Sie einen genaueren Blick auf die Antwort, Frage und Vorschlag. Nach der
of
sollte die async-Funktion, die ein array zurückgeben. Es funktioniert nicht und Francisco sagte;Ich glaube nicht, dass diese Antwort Adresse die erste Frage.
for-await-of
mit einer synchronen iterierbar (ein array, in unserem Fall) nicht gerade der Fall Durchlaufen gleichzeitig ein array mit asynchronen Operationen in jeder iteration. Wenn ich mich nicht Irre, mitfor-await-of
mit einer synchronen durchsuchbar über nicht-promise-Werte ist die gleiche wie mit einem einfachenfor-of
.InformationsquelleAutor Francisco Mateo
Statt
Promise.all
in Verbindung mitArray.prototype.map
(die keine Garantie für die Reihenfolge, in der diePromise
s behoben sind), benutze ichArray.prototype.reduce
, beginnend mit einer abgeschlossenenPromise
:Promise.resolve()
undawait promise;
?Das ist ziemlich cool. Bin ich Recht in der Annahme die Dateien werden in Reihenfolge gelesen und nicht alle auf einmal?
gibt ein bereits gelöst
Promise
Objekt, so dassreduce
hat einePromise
mit zu beginnen.await promise;
wird warten, bis die letztenPromise
in der Kette zu beheben. @GollyJer Die Dateien werden nacheinander verarbeitet werden, ein zu einer Zeit.Sehr cool Verwendung von reduzieren, danke für den Kommentar! Ich werde einfach zu zeigen, dass, im Gegensatz zu einigen der anderen Methoden erwähnt in den Kommentaren, dieser ist synchron, was bedeutet, dass die Dateien gelesen werden nacheinander und nicht parallel (da die nächste iteration von reduce-Funktion stützt sich auf die vorherigen iteration, es muss synchron sein).
Du meinst, sequentiellen, nicht synchron. Dies ist immer noch asynchron - wenn andere Dinge sind geplant, Sie werden zwischen den Iterationen hier.
InformationsquelleAutor Timothy Zorn
Den p-iteration Modul auf npm implementiert die Array-iteration Methoden, damit Sie verwendet werden können in einer sehr einfachen Art und Weise mit async/await.
Beispiel in Ihrem Fall:
some
eher alsforEach
. Danke!InformationsquelleAutor Antonio Val
Hier sind einige
forEachAsync
Prototypen. Hinweis: Sie müssenawait
Sie:Hinweis, während Sie können diese in Ihrem eigenen code, sollten Sie nicht diese in Bibliotheken verteilen Sie an andere (um zu vermeiden verschmutzen Ihre globals).
Solange der name eindeutig ist, in der Zukunft (wie ich benutzen würde
_forEachAsync
) dies zumutbar ist. Ich denke auch, es ist die schönste Antwort, denn es spart eine Menge boilerplate-code.Sie sollten eigenständige Funktionen. Wir haben die Module nicht belasten globals mit unseren persönlichen Sachen.
Das ist, um zu vermeiden verschmutzen anderer Leute code. Wenn der code gehört zu unserer persönlichen organisation, und die globals sind in einem gut identifizierten Datei (
globals.js
wäre gut) wir können hinzufügen, globals, wie wir.Sicher. Ich habe eine Warnung an Sie die Frage zum speichern der (nicht besonders produktiv) Diskussion hier.
InformationsquelleAutor Matt
Beide der oben genannten Lösungen arbeiten, aber Antonio macht den job mit weniger code, ist hier, wie es hat mir geholfen, lösen Daten aus meiner Datenbank, die aus mehreren verschiedenen untergeordneten refs und dann schieben Sie Sie alle in ein array und lösen es in einer Verheißung, nachdem alles getan ist:
InformationsquelleAutor Hooman Askari
es ist ziemlich schmerzlos zu pop ein paar Methoden in eine Datei verarbeiten asynchroner Daten in serialisierter Ordnung und geben einem eher konventionellen Geschmack, um Ihren code. Zum Beispiel:
nun, vorausgesetzt, die gespeichert bei './myAsync.js' Sie können tun, etwas ähnliches wie die unten in einem angrenzenden Datei:
InformationsquelleAutor Jay Edwards
Eine wichtige VORBEHALT ist: Die
await + for .. of
- Methode und dieforEach + async
Weise tatsächlich haben unterschiedliche Auswirkungen.Dass
await
im inneren eine echtefor
Schleife wird sicherstellen, dass alle asynchronen Aufrufe ausgeführt werden eins nach dem anderen. Und dieforEach + async
Weise Feuer aus, alle Verheißungen auf die gleiche Zeit, die ist schneller, aber manchmal überfordert (, wenn Sie einige DB-Abfrage oder besuchen Sie einige web-services mit Volumen-Beschränkungen und wollen nicht Feuer mit 100.000 Anrufe gleichzeitig).Können Sie auch
reduce + promise
(weniger elegant), wenn Sie nicht verwendenasync/await
wollen sicherstellen, dass Dateien gelesen werden einer nach dem anderen.Oder erstellen Sie eine forEachAsync zu helfen, aber im Grunde verwenden Sie die gleichen for-Schleife zugrunde.
forEach
- Zugriff auf die Indizes, anstatt sich auf iterability - und übergeben Sie den index für die callback.Sie können
Array.prototype.reduce
in einer Weise, die verwendet eine asynchrone Funktion. Ich habe Ihnen gezeigt, ein Beispiel in meiner Antwort: stackoverflow.com/a/49499491/2537258InformationsquelleAutor Leon li
Durch die Aufgabe, futurize und eine begehbare Liste, können Sie einfach tun
Hier ist, wie würden Sie diese Einrichtung,
Anderen Weg, um strukturiert den gewünschten code wäre
Oder vielleicht sogar mehr funktional orientierte
Dann von der übergeordneten Funktion
Wenn Sie wirklich wollten, mehr Flexibilität bei der Codierung, können Sie einfach diesen (für Spaß, ich bin mit den vorgeschlagenen Rohr-Forward-operator )
PS - ich habe nicht versucht, diesen code auf der Konsole, vielleicht haben einige Tippfehler... "straight freestyle, aus der Spitze der Kuppel!", als die 90er-Jahre Kinder sagen würden. :-p
InformationsquelleAutor Babakness
Neben @Bergi s Antwort, würde ich gerne eine Dritte alternative. Es ist sehr ähnlich wie @Bergi s Beispiel 2, aber statt warten auf jeden
readFile
individuell, erstellen Sie ein array von Versprechen, jede, die Sie erwarten am Ende.Beachten Sie, dass die Funktion übergeben
.map()
muss nicht seinasync
, dafs.readFile
gibt ein Promise-Objekt sowieso. Daherpromises
ist ein array von Promise-Objekte, die gesendet werden können, umPromise.all()
.In @Bergi s Antwort, die Konsole kann die log-Datei der Inhalt in Ordnung. Zum Beispiel, wenn eine wirklich kleine Datei vollständig zu Lesen, bevor Sie eine wirklich große Datei, wird protokolliert, selbst wenn die kleine Datei kommt nach die große Datei in der
files
array. Jedoch in meiner oben genannten Methode werden Sie garantiert das Konsole-log-Dateien in der gleichen Reihenfolge, wie Sie gelesen werden.InformationsquelleAutor chharvey
Derzeit das Array.forEach prototype-Eigenschaft nicht unterstützt asynchrone Operationen, aber wir können unsere eigene poly-fill für unsere Bedürfnisse.
Und das ist es! Sie haben jetzt eine asynchrone forEach-Methode zur Verfügung, die auf beliebige arrays definiert sind, die nach diesen Operationen.
Let ' s test...
Könnten wir das gleiche tun für einige andere array-Funktionen wie map...
... und so weiter 🙂
Einige Dinge zu beachten:
Array.prototype.<yourAsyncFunc> = <yourAsyncFunc>
verfügen nicht über diese Funktion zur VerfügungInformationsquelleAutor Beau
Ähnlich wie Antonio Val
p-Schleife
, eine alternative npm-Modul istasync-af
:Alternativ
async-af
hat eine statische Methode (log/logAF) , protokolliert die Ergebnisse der verspricht:Jedoch der wichtigste Vorteil der Bibliothek ist, dass Sie können Kette asynchrone Methoden, etwas zu tun:
async-af
InformationsquelleAutor Scott Rudiger
Bergi ' s Lösung funktioniert gut, wenn
fs
ist Versprechen basiert.Sie können
bluebird
,fs-extra
oderfs-promise
.Jedoch die Lösung für Knoten nativen
fs
Bibliothek ist wie folgt:Hinweis:
require('fs')
zwangsweise nimmt die Funktion als 3. Argumente, sonst wirft Fehler:InformationsquelleAutor myDoggyWritesCode