JavaScript unter der Haube: Ereignisschleife
Lassen Sie uns JavaScript beherrschen, indem wir seine Funktionsweise von Grund auf untersuchen
Sind Sie jemals mit undefinierten Fehlern konfrontiert oder hatten Sie Schwierigkeiten, den Gültigkeitsbereich einer Variablen zu identifizieren?
Es ist wirklich zeitaufwändig, Fehler zu debuggen, ohne zu wissen, wie der Code funktioniert.
In diesem Blog werde ich demonstrieren, wie fortschrittliche Konzepte wie event loopin Bezug auf execution context, call stack, und callback queuetatsächlich funktionieren.
Ein Haftungsausschluss – Die Konzepte sind unglaublich wissensintensiv und miteinander verbunden, also bitte nicht einmal mit den Augen blinzeln!
JavaScript-Engine
Die V8-Engine von Google ist ein bekanntes Beispiel für eine JavaScript-Engine. Beispielsweise verwenden Chrome und Node.js beide die V8-Engine. Grundsätzlich besteht der V8-Motor aus zwei Teilen —
- Call Stack: Der gesamte Code wird darin ausgeführt. Es funktioniert wie die Stack-Datenstruktur, dh nach dem LIFO-Konzept (Last In First Out).
- Memory Heap: Wo die Speicherzuweisung erfolgt. Im Gegensatz zur Heap-Datenstruktur ist es nur ein Speicher.
Der Global Execution Context oder GEC ist der standardmäßige Ausführungskontext, der von der JavaScript-Engine erstellt wird, wenn eine Skriptdatei empfangen wird.
Jeglicher JavaScript-Code, der sich nicht in einer Funktion befindet, wird in ausgeführt GEC. Die folgenden Schritte werden ausgeführt in GEC—
- Konstruieren Sie einen Speicherplatz, um alle Variablen und Funktionen auf globaler Ebene zu speichern
- Generieren Sie ein globales Objekt.
- Generieren Sie das Schlüsselwort
this
Je nachdem, wo Ihr Code ausgeführt wird, wird bestimmt, wo thissich befindet. Beispielsweise zeigt es in Node.js auf ein bestimmtes globales Objekt, während es im Browser auf das windowObjekt zeigt.
Aufrufstapel (oder Funktionsausführungsstapel)
JavaScript ist single-threaded, wie Sie bereits gehört haben. Aber was bedeutet es eigentlich?
Dies bedeutet, dass eine JavaScript-Engine nur eine call stackoder enthält function execution stack.
- Wie wir wissen, wird die JS-Engine jedes Mal, wenn der Compiler Ihren Code zum ersten Mal durchsucht, vom Compiler aufgefordert, ein
Global Execution Contextoder zu erstellenGECund es in dieCall Stack. - Ihr gesamter Code wird nacheinander in ausgeführt
Global Execution Contextund weist Speicher für die Funktionsdefinition oder Variablendeklaration zu und speichert ihn dort. - Aber wenn ein Funktionsaufruf gefunden wird, wird ein
Functional Execution ContextoderFECerstellt, um den Code der Funktion auszuführen, und dann wird es am Anfang dercall stack. - Der Interpreter entfernt eine Funktion
call stackjedes Mal, wenn die Funktion beendet wird. Eine Funktion wird beendet – wenn sie das Ende ihres Gültigkeitsbereichs oder eine return-Anweisung erreicht. - Schließlich wird die Ausführung Ihres gesamten Codes
GECaus derCall Stack.
Keine Sorge, wir demonstrieren es an einem Beispiel.
function f1{
console.log('f1');
}
f1();
console.log('end');
Schritt 2: — In unserem Beispiel wird die erste Zeile ausgeführt, die f1. Ein Speicher wird für f1seine Definition zugewiesen und gespeichert.
Schritt 3: — In der 2. Zeile wird eine Funktion aufgerufen. Für diesen Funktionsaufruf wird ein Function Execution Context oder FECerstellt und über dem gespeichert Call Stack.
Schritt 4: — Jetzt wird f1()das Ganze Zeile für Zeile ausgeführt und nach Abschluss der Ausführung aus der entfernt Call Stack.
Schritt 5: — Dann wird die letzte Zeile console.log('end')ausgeführt und 'end' auf der Konsole ausgegeben. Schließlich wird die Ausführung Ihres gesamten Codes Global Execution Contextaus der Call Stack.
Wie verwaltet JS asynchrone Aufgaben?
JavaScript, wie wir alle bekannt sind, ist eine synchrone Singlethread- Sprache (jeweils eine Aufgabe), und der einzelne Thread, der ausgeführt wird, führt call stacksofort alles aus, was darin enthalten ist.
Aber was ist, wenn wir nach 5 Sekunden etwas ausführen müssen? Können wir das drinnen anziehen call stack?
Nein, können wir nicht. Weil call stackes keinen Timer hat. Aber wie können wir das tun?
Hier kommt die JavaScript-Laufzeit ins Spiel.
Es kann untröstlich sein, wenn ich Ihnen jetzt sage, dass setTimeout()es kein Teil von JavaScript ist, obwohl alle console.log()DOM - Ereignisse die Teile von Web-APIs sind , die den Zugriff auf die JavaScript-Engine ermöglichen , um alle ihre Eigenschaften im Global Execution Context (GEC) zu verwenden das globale Objekt window. Diese Web-APIs werden als asynchron bezeichnet .
Was ist die Rückrufwarteschlange?
Eine Warteschlange von Aufgaben, die als „Rückrufwarteschlange“ oder „Aufgabenwarteschlange“ bezeichnet wird, ist eine Warteschlange, die ausgeführt wird, nachdem die aktuellen Aufgaben des Aufrufstapels abgeschlossen wurden. Aufgaben, die in der Web-API registriert sind, werden von der Web-API in die Callback-Warteschlange verschoben.
Die Callback-Warteschlange funktioniert wie eine Warteschlangen-Datenstruktur, was bedeutet, dass Aufgaben in FIFO-Reihenfolge (first in, first out) behandelt werden, im Gegensatz zu einem Aufrufstapel, was bedeutet, dass Aufgaben in der Reihenfolge behandelt werden, in der sie der Warteschlange hinzugefügt wurden.
Was ist eine Ereignisschleife?
Eine JavaScript-Ereignisschleife fügt dem Aufrufstapel in FIFO-Reihenfolge eine Aufgabe aus der Callback-Warteschlange hinzu, sobald der Aufrufstapel leer ist.
Die Ereignisschleife wird blockiert, wenn der Aufrufstapel derzeit Code ausführt und keine zusätzlichen Aufrufe aus der Warteschlange hinzufügt, bis der Stapel wieder leer ist. Dies liegt daran, dass JavaScript-Code in einer Run-to-Completion-Methode ausgeführt wird.
Lassen Sie uns die obigen Konzepte anhand eines Beispiels verstehen.
- Zunächst
Global Execution Contextwird unser Code in unserem erstelltcall stackundGECunser Code Zeile für Zeile ausgeführt. GECführt die erste Zeile aus und gibt 'Start' auf unserer Konsole aus.- Beim Ausführen der zweiten Zeile wird
setTimeout()die Web-API aufgerufen undsetTimeout()gibt dann den Zugriff auf die Timer-Funktion. Dann können Sie5000mseine Verzögerungszeit einstellen. - Wenn Sie die
callBack()Funktion über die übergebensetTimeout(),callBack()wird die als Rückruf über die Web-Web-API registriert. - Und
GECführt dann die erste Zeile aus und gibt 'End' auf der Konsole aus. - Wenn der gesamte Code ausgeführt wurde,
GECwird er aus unserer entferntcall stack. - Danach
5000 millisecondwird diecallBack()Funktion, die in registriert ist, in dieweb APIverschobencall Back Queue. Event loopsetzt diecallBack()Funktion in diecall StackWenn es fertig ist, ist es alles Arbeit. Und schließlich wird diecallBack()Funktion ausgeführt und 'Call Back' in die Konsole ausgegeben.
function f1() {
console.log('f1');
}
function f2() {
console.log('f2');
}
function main() {
console.log('main');
setTimeout(f1, 0);
f2();
}
main();
Wenn Sie denken, dass „f1“ vor „f2“ gedruckt wird, dann liegen Sie falsch. Es wird sein -
main
f2
f1
Der besprochene Mechanismus von JavaScript eignet sich für jede Callback-Funktion oder API-Anfrage.
Lassen Sie uns Schritt für Schritt beobachten, wie das zweite Beispiel in der Laufzeitumgebung funktioniert.
- Zuerst
GECwird in erstelltcall stackund dann Code Zeile für Zeile in ausgeführtGEC. Es speichert alle Funktionsdefinitionen im Memory Heap . - Wenn der
main()aufgerufen wird,Function Execution Context (FEC)wird a erstellt und gelangt dann in den Aufrufstapel. Danachmain()wird der gesamte Code der Funktion Zeile für Zeile ausgeführt. - Es hat ein Konsolenprotokoll, um das Wort main zu drucken. Das wird also
console.log('main')ausgeführt und geht aus dem Stack. - Die
setTimeout()Browser-API findet statt. Die Callback-Funktion stellt es in die Callback-Warteschlange. Aber im Stack erfolgt die Ausführung wie gewohnt, gelangt alsof2()in den Stack. Das Konsolenprotokoll vonf2()executes. Beide gehen aus dem Stapel. - Und dann
main()springt der auch aus dem Stapel. - Die Ereignisschleife erkennt, dass der Call-Stack leer ist und es eine Callback-Funktion in der Warteschlange gibt. Die Callback-Funktion
f1()wird also von derevent loop. Die Ausführung beginnt. Das Konsolenprotokoll wird ausgeführt und erscheintf1()auch aus dem Stack. Und schließlich befindet sich nichts anderes im Stapel und in der Warteschlange, um weiter ausgeführt zu werden.
Es ist meine Praxis und Notiz. Wenn Sie es nützlich fanden, zeigen Sie bitte Ihre Unterstützung, indem Sie unten auf das Klatschen-Symbol klicken. Du kannst mir auf Medium folgen .

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































