„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Ereignisschleife

Ereignisschleife

Veröffentlicht am 23.08.2024
Durchsuche:486

Event Loop

Einführung
JavaScript wird meist in einem einzelnen Thread in Node.js und im Browser ausgeführt (mit einigen Ausnahmen wie Worker-Threads, die nicht Gegenstand des aktuellen Artikels sind). In diesem Artikel werde ich versuchen, den Mechanismus der Parallelität bei Node.js zu erklären, der die Ereignisschleife darstellt.

Bevor Sie mit dem Lesen dieses Artikels beginnen, sollten Sie mit dem Stack und seiner Funktionsweise vertraut sein. Ich habe in der Vergangenheit über diese Idee geschrieben, also schauen Sie sich Stack & Heap an – Beginnen Sie nicht mit dem Codieren, ohne sie zu verstehen – Moshe Binieli | Medium

Einführungsbild
Beispiele
Ich glaube, dass das Lernen anhand von Beispielen am besten ist, deshalb beginne ich mit 4 einfachen Codebeispielen. Ich werde die Beispiele analysieren und dann in die Architektur von Node.js eintauchen.

Beispiel 1:
console.log(1);
console.log(2);
console.log(3);
// Ausgabe:
// 1
// 2
// 3
Dieses Beispiel ist ziemlich einfach. Im ersten Schritt geht console.log(1) in den Aufrufstapel, wird ausgeführt und dann entfernt. Im zweiten Schritt geht console.log(2) in den Aufrufstapel und wird ausgeführt und dann entfernt, und so weiter für console.log(3).

Visualisierung des Aufrufstapels für Beispiel 1
Beispiel 2:
console.log(1);
setTimeout(function foo(){
console.log(2);
}, 0);
console.log(3);
// Ausgabe:
// 1
// 3
// 2
Wir können in diesem Beispiel sehen, dass wir setTimeout sofort ausführen, also würden wir erwarten, dass console.log(2) vor console.log(3) steht, aber das ist nicht der Fall und lassen Sie uns den Mechanismus dahinter verstehen.

Grundlegende Event-Loop-Architektur (wir werden später näher darauf eingehen)

Stack & Heap: Schauen Sie sich meinen Artikel dazu an (ich habe am Anfang dieses Artikels einen Link hinzugefügt)
Web-APIs: Sie sind in Ihren Webbrowser integriert und können Daten aus dem Browser und der umgebenden Computerumgebung offenlegen und damit nützliche komplexe Dinge tun. Sie sind nicht Teil der JavaScript-Sprache selbst, sondern basieren auf der JavaScript-Kernsprache und bieten Ihnen zusätzliche Superkräfte, die Sie in Ihrem JavaScript-Code verwenden können. Die Geolocation-API bietet beispielsweise einige einfache JavaScript-Konstrukte zum Abrufen von Standortdaten, sodass Sie beispielsweise Ihren Standort auf einer Google-Karte einzeichnen können. Im Hintergrund verwendet der Browser tatsächlich einen komplexen Code auf niedrigerer Ebene (z. B. C), um mit der GPS-Hardware des Geräts (oder was auch immer verfügbar ist, um Positionsdaten zu ermitteln) zu kommunizieren, Positionsdaten abzurufen und sie zur Verwendung an die Browserumgebung zurückzugeben in Ihrem Code. Aber auch diese Komplexität wird Ihnen durch die API entzogen.
Ereignisschleife und Rückrufwarteschlange: Die Funktionen, die die Web-Apis-Ausführung abgeschlossen haben, werden in die Rückrufwarteschlange verschoben. Dies ist eine reguläre Warteschlangendatenstruktur, und die Ereignisschleife ist dafür verantwortlich, die nächste Funktion aus der Rückrufwarteschlange zu entfernen und die Funktion an zu senden der Aufrufstapel zum Ausführen der Funktion.
Reihenfolge der Ausführung

Alle Funktionen, die sich derzeit im Aufrufstapel befinden, werden ausgeführt und dann aus dem Aufrufstapel entfernt.
Wenn der Aufrufstapel leer ist, werden alle in der Warteschlange befindlichen Aufgaben einzeln auf den Aufrufstapel gelegt und ausgeführt, und dann werden sie vom Aufrufstapel entfernt.
Lassen Sie uns Beispiel 2 verstehen

Die Methode

console.log(1) wird aufgerufen, auf dem Aufrufstapel abgelegt und ausgeführt.

    Die Methode
  1. setTimeout wird aufgerufen und auf dem Aufrufstapel platziert und ausgeführt. Diese Ausführung erstellt einen neuen Aufruf an die setTimeout-Web-API für 0 Millisekunden, wenn sie beendet ist (sofort, oder genauer gesagt, dann). Sagen Sie besser „so schnell wie möglich“). Die Web-API verschiebt den Anruf in die Rückrufwarteschlange.

  2. Die Methode
  3. console.log(3) wird aufgerufen, auf dem Aufrufstapel abgelegt und ausgeführt.

  4. Die Ereignisschleife erkennt, dass der Aufrufstapel leer ist, entnimmt die „foo“-Methode aus der Rückrufwarteschlange und platziert sie im Aufrufstapel. Anschließend wird console.log(2) ausgeführt.

Visualisierung des Prozesses für Beispiel 2
Der Verzögerungsparameter in setTimeout(function, delay) steht also nicht für die genaue Zeitverzögerung, nach der die Funktion ausgeführt wird. Es steht für die Mindestwartezeit, nach der die Funktion irgendwann ausgeführt wird.

Beispiel 3:
console.log(1);
setTimeout(function foo() {
console.log(‘foo’);
}, 3500);
setTimeout(function boo() {
console.log(‘boo’);
}, 1000);
console.log(2);
// Ausgabe:
// 1
// 2
// 'boo'
// 'foo'

Visualisierung des Prozesses für Beispiel 3
Beispiel 4:
console.log(1);
setTimeout(function foo() {
console.log(‘foo’);
}, 6500);
setTimeout(function boo() {
console.log(‘boo’);
}, 2500);
setTimeout(function baz() {
console.log(‘baz’);
}, 0);
for (const value of [‘A’, ‘B’]) {
console.log(Wert);
}
Funktion zwei() {
console.log(2);
}
zwei();
// Ausgabe:
// 1
// 'A'
// 'B'
// 2
// 'baz'
// 'boo'
// 'foo'

Visualisierung des Prozesses für Beispiel 4
Die Ereignisschleife führt alle in der Aufgabenwarteschlange wartenden Rückrufe aus. Innerhalb der Aufgabenwarteschlange werden die Aufgaben grob in zwei Kategorien eingeteilt, nämlich Mikroaufgaben und Makroaufgaben.

Makroaufgaben (Aufgabenwarteschlange) und Mikroaufgaben
Genauer gesagt gibt es tatsächlich zwei Arten von Warteschlangen.

  1. Die Makro-Aufgabenwarteschlange (oder einfach Aufgabenwarteschlange genannt).
  2. Die Mikroaufgaben-Warteschlange.

Es gibt noch ein paar weitere Aufgaben, die in die Makro- und Mikroaufgaben-Warteschlange gestellt werden, aber ich werde die häufigsten behandeln.

Gemeinsame Makroaufgaben sind setTimeout, setInterval und setImmediate.
Gängige Mikrotasks sind „process.nextTick“ und „Promise Callback“.
Reihenfolge der Ausführung
Alle Funktionen, die sich derzeit im Aufrufstapel befinden, werden ausgeführt und dann vom Aufrufstapel entfernt.
Wenn der Aufrufstapel leer ist, werden alle in der Warteschlange befindlichen Mikroaufgaben nacheinander auf den Aufrufstapel gelegt und ausgeführt, und dann werden sie vom Aufrufstapel entfernt.
Wenn sowohl der Aufrufstapel als auch die Mikroaufgabenwarteschlange leer sind, werden alle in der Warteschlange befindlichen Makroaufgaben nacheinander auf den Aufrufstapel gelegt und ausgeführt. Anschließend werden sie aus dem Aufrufstapel entfernt.
Beispiel 5:
console.log(1);
setTimeout(function foo() {
console.log(‘foo’);
}, 0);
Promise.resolve()
.then(function boo() {
console.log(‘boo’);
});
console.log(2);
// Ausgabe:
// 1
// 2
// 'boo'
// 'foo'
Die Methode console.log(1) wird aufgerufen, auf dem Aufrufstapel platziert und ausgeführt.
SetTimeout wird ausgeführt, das console.log(‘foo’) wird in die SetTimeout-Web-API verschoben und 0 Millisekunden danach in die Makro-Task-Warteschlange.
Promise.resolve() wird aufgerufen, es wird aufgelöst und dann wird die Methode .then() in die Micro-Task-Warteschlange verschoben.
Die Methode console.log(2) wird aufgerufen, auf dem Aufrufstapel platziert und ausgeführt.
Wenn die Ereignisschleife feststellt, dass der Aufrufstapel leer ist, nimmt sie zunächst die Aufgabe aus der Micro-Task-Warteschlange, bei der es sich um die Promise-Aufgabe handelt, legt console.log(‘boo’) auf dem Aufrufstapel ab und führt sie aus.
Die Ereignisschleife erkennt, dass der Aufrufstapel leer ist, dann erkennt sie, dass die Mikroaufgabe leer ist, nimmt dann die nächste Aufgabe aus der Makroaufgabenwarteschlange, die SetTimeout-Aufgabe, und fügt das console.log('foo') ein. auf dem Call-Stack und führt es aus.

Visualisierung des Prozesses für Beispiel 5
Erweitertes Verständnis der Ereignisschleife
Ich habe darüber nachgedacht, über die niedrige Ebene der Funktionsweise des Event-Loop-Mechanismus zu schreiben. Es könnte ein eigenständiger Beitrag sein, also habe ich beschlossen, eine Einführung in das Thema zu bringen und gute Links anzuhängen, die das Thema ausführlich erläutern.

Ereignisschleife auf niedrigerer Ebene erklärt
Wenn Node.js startet, initialisiert es die Ereignisschleife, verarbeitet das bereitgestellte Eingabeskript (oder fügt es in die REPL ein), das asynchrone API-Aufrufe durchführen, Timer planen oder Process.nextTick() aufrufen kann, und beginnt dann mit der Verarbeitung der Ereignisschleife.

Das folgende Diagramm zeigt einen vereinfachten Überblick über die Reihenfolge der Operationen der Ereignisschleife. (Jedes Feld wird als „Phase“ der Ereignisschleife bezeichnet. Schauen Sie sich bitte das Einführungsbild an, um ein gutes Verständnis des Zyklus zu erhalten.)

Vereinfachte Übersicht über die Reihenfolge der Operationen in der Ereignisschleife
Jede Phase verfügt über eine FIFO-Warteschlange mit auszuführenden Rückrufen (ich sage es hier vorsichtig, da es je nach Implementierung möglicherweise eine andere Datenstruktur gibt). Obwohl jede Phase auf ihre eigene Weise etwas Besonderes ist, führt die Ereignisschleife im Allgemeinen beim Eintritt in eine bestimmte Phase alle für diese Phase spezifischen Vorgänge aus und führt dann Rückrufe in der Warteschlange dieser Phase aus, bis die Warteschlange erschöpft ist oder die maximale Anzahl an Rückrufen erreicht ist hat ausgeführt. Wenn die Warteschlange erschöpft ist oder das Rückruflimit erreicht ist, geht die Ereignisschleife zur nächsten Phase über und so weiter.

Phasenübersicht
Timer: In dieser Phase werden von setTimeout() und setInterval() geplante Rückrufe ausgeführt.
Ausstehende Rückrufe: führt E/A-Rückrufe aus, die auf die nächste Schleifeniteration verschoben werden.
Leerlauf, Vorbereiten: nur intern verwendet.
Umfrage: Neue I/O-Ereignisse abrufen; I/O-bezogene Rückrufe ausführen (fast alle mit Ausnahme von Close-Rückrufen, denen, die von Timern geplant werden, und setImmediate()); Der Knoten wird hier gegebenenfalls blockieren.
Prüfen: Hier werden setImmediate()-Callbacks aufgerufen.
Close-Callbacks: Einige Close-Callbacks, z.B. socket.on('close', ...).
Wie passen die vorherigen Schritte hier hinein?
Die vorherigen Schritte nur mit der „Callback-Warteschlange“ und dann mit „Makro- und Mikro-Warteschlangen“ waren abstrakte Erklärungen zur Funktionsweise der Ereignisschleife.

Es ist noch etwas WICHTIGES zu erwähnen: Die Ereignisschleife sollte die Mikroaufgabenwarteschlange vollständig verarbeiten, nachdem sie eine Makroaufgabe aus der Makroaufgabenwarteschlange verarbeitet hat.

Schritt 1: Die Ereignisschleife aktualisiert die Schleifenzeit auf die aktuelle Zeit für die aktuelle Ausführung.
Schritt 2: Micro-Queue wird ausgeführt.
Schritt 3: Eine Aufgabe aus der Timer-Phase wird ausgeführt.
Schritt 4: Überprüfen Sie, ob sich etwas in der Mikrowarteschlange befindet, und führen Sie die gesamte Mikrowarteschlange aus, wenn etwas vorhanden ist.
Schritt 5: Kehrt zu Schritt 3 zurück, bis die Timer-Phase leer ist.
Schritt 6: Eine Aufgabe aus der Phase „Ausstehende Rückrufe“ wird ausgeführt.
Schritt 7: Überprüfen Sie, ob sich etwas in der Mikro-Warteschlange befindet, und führen Sie die gesamte Mikro-Warteschlange aus, wenn etwas vorhanden ist.
Schritt 8: Kehrt zu Schritt 6 zurück, bis die Phase „Ausstehende Rückrufe“ leer ist.
Und dann Leerlauf … Mikro-Warteschlange … Umfrage … Mikro-Warteschlange … Überprüfen … Mikro-Warteschlange … Rückrufe schließen und dann beginnt es von vorne.
Deshalb habe ich einen schönen Überblick darüber gegeben, wie die Event-Schleife tatsächlich hinter den Kulissen funktioniert. Es fehlen viele Teile, die ich hier nicht erwähnt habe, weil die eigentliche Dokumentation einen tollen Job bei der Erklärung leistet, für die ich tolle Links bereitstellen werde Um die Dokumentation zu verstehen, ermutige ich Sie, 10–20 Minuten zu investieren und sie zu verstehen.

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/atulnagose1499/event-loop-4fck?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3