Wie werden asynchrone Schleifen in JavaScript der Reihe nach oder parallel ausgeführt?
Bevor ich asynchrone Magie mache, möchte ich Sie daran erinnern, wie klassische synchrone Schleifen aussehen.
Synchrone Schleifen
Vor langer Zeit habe ich Loops so geschrieben (vielleicht auch Sie):
for (var i=0; i < array.length; i++) { var item = array[i];
Dieser Zyklus ist gut und schnell. Aber er hat viele Probleme mit der Lesbarkeit und Unterstützung. Nach einer Weile gewöhnte ich mich an die beste Version:
array.forEach((item) => {
JavaScript entwickelt sich sehr schnell. Neue Funktionen und Syntax werden angezeigt. Eine meiner Lieblingsverbesserungen ist async / await .
Jetzt benutze ich diese Syntax ziemlich oft. Und manchmal gibt es Situationen, in denen ich asynchron etwas mit Array-Elementen tun muss.
Asynchrone Schleifen
Wie verwendet man await
im Körper der Schleife? Versuchen wir einfach, eine asynchrone Funktion zu schreiben und erwarten die Aufgabe, jedes Element zu verarbeiten:
async function processArray(array) { array.forEach(item => {
Dieser Code gibt einen Fehler aus. Warum? Weil wir das await
in einer synchronen Funktion nicht verwenden können. Wie Sie sehen können, ist processArray
eine asynchrone Funktion. Die anonyme Funktion, die wir für forEach
ist jedoch synchron .
Was kann man dagegen tun?
1. Warten Sie nicht auf das Ergebnis der Ausführung
Wir können eine anonyme Funktion als asynchron definieren:
async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); }
forEach
wartet jedoch nicht auf den Abschluss der Aufgabe. forEach
ist eine synchrone Operation. Sie wird einfach die Aufgaben starten und weitermachen. Schauen wir uns einen einfachen Test an:
function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) {
In der Konsole sehen wir:
Done! 1 2 3
In einigen Situationen kann dies ein normales Ergebnis sein. In den meisten Fällen ist dies jedoch keine geeignete Logik.
2. Den Zyklus nacheinander verarbeiten
Um auf das Ergebnis der Ausführung des Schleifenkörpers zu warten, müssen wir zur guten alten "for" -Schleife zurückkehren. Aber dieses Mal werden wir seine neue Version mit dem Konstrukt for..of
verwenden (Dank des Iterationsprotokolls ):
async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); }
Dies gibt uns das erwartete Ergebnis:
1 2 3 Done!
Jedes Element des Arrays wird nacheinander verarbeitet. Aber wir können die Schleife parallel laufen lassen!
3. Parallelschaltung der Schleife
Sie müssen den Code leicht ändern, um die Vorgänge parallel zu starten:
async function processArray(array) {
Dieser Code kann mehrere delayLog
Tasks delayLog
ausführen. Aber seien Sie vorsichtig mit großen Arrays. Zu viele Aufgaben können für die CPU und den Speicher zu schwierig sein.
Bitte verwechseln Sie auch nicht die "parallelen Aufgaben" aus dem Beispiel mit echter Parallelität und Threads. Dieser Code garantiert keine parallele Ausführung. Alles hängt vom Körper der Schleife ab (im Beispiel ist es delayedLog
). Netzwerkanforderungen, Webworker und einige andere Aufgaben können parallel ausgeführt werden.