Tauchen Sie tief in die Javascript-Interna ein
Interne Funktionsweise der Javascript-Engine, Ereignisschleife, Web-APIs, Ereigniswarteschlangen und Rückrufe.
Einführung
Haben Sie sich jemals vorgestellt, was passiert wäre, wenn es kein Javascript gäbe? Ohne Javascript könnten Sie keine Filme auf Netflix streamen, bei Amazon einkaufen oder Videos auf Youtube ansehen. Fast jede andere Website verwendet Javascript und macht die Webseite interaktiv.
Bevor Javascript erfunden wurde, bestand das Internet nur aus einfachen HTML- Seiten. HTML und CSS verleihen einer Webseite Struktur und Stil. Aber Javascript macht die Webseite dynamisch . Sie können Ihre Anmeldedaten eingeben und sich auf einer Website anmelden, Online-Transaktionen durchführen oder Spiele spielen. Javascript macht alles möglich.
Eine der auf Stack-overflow durchgeführten Umfragen ergab, dass Javascript die höchste Anzahl an Repos auf GitHub hat. Jedes Jahr werden neue Frameworks und Bibliotheken in Javascript entwickelt. Die Sprache hat das Internet wirklich verändert und das Leben der Menschen vereinfacht.
Hintergrund
Vor zwei Jahren arbeitete ich an einem Nebenprojekt und verwendete zum ersten Mal Javascript. Da ich seit dem letzten Jahrzehnt ein erfahrener Programmierer bin, habe ich mich mit der Syntax gut vertraut gemacht und innerhalb von drei Monaten eine gute Beherrschung entwickelt.
Im Laufe der Monate schnitt die von mir entwickelte Webseite nicht mehr gut ab. Das Laden dauerte lange und begann sich auf die Kunden auszuwirken. Also habe ich tiefgründig nachgeforscht, um die Grundursache zu ermitteln.
Nach schlaflosen Nächten war ich schließlich am Ende meiner Weisheit und kurz davor, aufzugeben. Ich beschloss jedoch, einen letzten Versuch zu wagen. Schließlich dachte ich darüber nach, ein gründliches Verständnis dafür zu erlangen, wie Javascript intern funktioniert. Ich habe viele Ressourcen herangezogen und konnte den Fehler in meinem Code schließlich innerhalb von zwei Tagen beheben.
Ingenieure konzentrieren sich im Allgemeinen darauf, neue Dinge zu bauen. Die Tools und Frameworks, die wir verwenden, verbergen den größten Teil der Komplexität vor uns. Auf unserer Reise vergessen wir oft, wie die Dinge hinter den Kulissen tatsächlich funktionieren. Es ist notwendig, die interne Funktionsweise jedes von uns verwendeten Tools zu kennen. Ein gutes Verständnis der Interna hilft uns, das Problem einzugrenzen und eine pragmatische Lösung zu finden.
In diesem Artikel werfen wir einen Blick darauf, was hinter den Kulissen passiert, wenn Javascript vom Browser ausgeführt wird. Wir werden einen Blick auf die Javascript-Engine werfen und ihre Funktionsweise verstehen. Wir werden die verschiedenen Komponenten sehen, die an der Javascript-Laufzeit beteiligt sind, und Klarheit über die Ereignisschleife und die Ereigniswarteschlange gewinnen. Obwohl diese Begriffe für Sie möglicherweise neu sind, wird in dem Artikel versucht, sie zu vereinfachen. Beginnen wir mit unserer Suche nach der Beherrschung der Interna von Javascript.
Javascript
Javascript ist eine hochinterpretierte Sprache. Im Gegensatz zu C oder C++ müssen wir keinen Javascript-Code kompilieren und ihn dann ausführen. Javascript-Code wird zunächst in Bytecode kompiliert und dann in Code auf Maschinenebene übersetzt.
Hochsprachen wie Java, C, C++, C# unterstützen Multithreading. Mit diesen Sprachen können Programmierer mehrere Threads erstellen und die Aufgaben in verschiedenen Threads ausführen. So können wir Aufgaben auf mehreren CPUs starten und Rechenressourcen effizient nutzen.
Im Gegensatz dazu ist Javascript Single-Threaded. Dies bedeutet, dass zu jedem Zeitpunkt nur ein einziger Ausführungsthread vorhanden ist. Wenn Sie eine zeitaufwändige Javascript-Funktion ausführen, friert die Webseite ein. Möglicherweise ist Ihnen beim Surfen schon oft der Fehler „ Website reagiert nicht“ aufgefallen .
Lassen Sie uns eine kurze Demo machen und die Funktionsweise in Aktion sehen. Ich habe Twitter geöffnet und kann auf die einzelnen Tabs wie Trending, usw. klicken.NewsSports
Jetzt developerschreibe ich in meiner Konsole eine Funktion, die eine Endlosschleife enthält . Nachfolgend finden Sie die Definition der Funktion.
function infiniteLoop() {
for(i=0; i < 100000; ) {
}
}
infiniteLoop()
SportsDas folgende GIF zeigt, dass ich die Registerkarte nicht in oder ändern kann Entertaintment.
Da die Funktion eine Endlosschleife enthält, wird sie endlos weiter ausgeführt. Wenn ich verschiedene Tabs auswähle, soll der Browser das clickEreignis verarbeiten und dementsprechend den Inhalt des angeklickten Tabs anzeigen. Ich kann keine andere Registerkarte auswählen, da Javascript die Funktion bereits ausführt infiniteLoop.
Wie im obigen Beispiel zu sehen ist, können wir in Javascript jeweils nur eine Funktion ausführen. Nun fragen Sie sich vielleicht, wie der Browser komplexe Websites in Sekundenbruchteilen laden kann.
In den folgenden Abschnitten werden wir verstehen, wie Javascript diese Magie hinter den Kulissen vollbringt. Lassen Sie uns nun den Kern von Javascript verstehen, dh die Javascript Engine.
Javascript-Engine
Jeder Browser verfügt über eine eigene Javascript-Engine. Zum Beispiel: Chrome verwendet die V8-Engine, während Firefox die SpiderMonkey-Engine verwendet. Die Engine ist für die zeilenweise Ausführung des Javascript-Codes verantwortlich. Nachfolgend finden Sie eine Liste gängiger Browser und ihrer Javascript-Engines.
Die Javascript-Engine besteht aus einem Heap und einem Stack . Lassen Sie uns die Funktionsweise dieser beiden Elemente verstehen.
Haufen
Der Heap ist für die Speicherung der Funktionsdefinitionen und Objektvariablen verantwortlich. Es enthält alle Objekte, auf die der Code verweist.
Objekte werden dynamisch im Heap erstellt. Die Arbeitsweise ist ähnlich wie bei Java. Immer wenn das Objekt von einer Funktion referenziert wird, wird es vom Heap abgerufen.
function bar() {
var player = { "firstName": "Shubhman",
"lastName": "Gill"
}
var teams = ["India", "NewZealand"]
i =0
a = 10
console.log("In the function bar")
}
bar()
Objects on Heap
Stapel
Der Stack ist eine LIFO-Datenstruktur (Last In First Out). Jedes Mal, wenn eine Funktion ausgeführt wird, werden die lokalen Variablen der Funktion auf den Stapel verschoben. Sobald die Ausführung der Funktion abgeschlossen ist, wird sie vom Stapel entfernt. Wenn eine Funktion während der Ausführung eine neue Funktion aufruft, wird die neue Funktion ebenfalls auf den Stapel verschoben. Die Engine führt die Funktion aus, die sich oben im Stapel befindet.
Die Funktionen am unteren Ende des Stapels nehmen ihre Ausführung wieder auf, sobald alle darüber liegenden Funktionen zurückkehren. Falls eine Funktion einen Fehler auslöst, wird ein Stack-Trace auf dem ausgegeben console. Der Stack-Trace besteht aus einer Kette von Funktionen, die aufgerufen wurden, als eine Ausnahme ausgelöst wurde. Schauen wir uns ein Beispiel an.
Ich werde den obigen Code in meinem Browser ausführen. Und fügen Sie der Funktion einen Haltepunkt hinzu city.
Wie oben zu sehen ist, wurde das Skript bei der Ausführung am Haltepunkt in der Funktion gestoppt city. Auf der rechten Seite im Call StackAbschnitt sehen Sie die cityFunktion oben.
Die Call Stackbesteht aus allen bisher aufgerufenen Funktionen. Und die aktuellste Funktion steht ganz oben. Sobald die Ausführung der Funktion abgeschlossen ist, wird sie vom Stapel entfernt.
Im Bild unten sehen Sie, dass die Funktion cityentfernt wurde und die Ausführung der Funktion streetin Zeile 9 fortgesetzt wird.
Wie oben gesehen, kann Javascript jeweils nur eine Funktion ausführen und es gibt nur einen Ausführungsthread. Sie können im Ausführungsstapel nicht mehrere Funktionen gleichzeitig ausführen.
Nehmen wir an, wir haben eine Funktion, die einen HTTPAufruf durchführt und Daten von einer anderen Website abruft. Was würde passieren, wenn der Server langsam ist und die Ausführung der Funktion lange dauert? Wir können keine andere Funktion ausführen und die Benutzererfahrung wäre sehr schlecht.
Passiert das in der realen Welt? Nein, komplexe Websites wie Facebook.com , Twitter.com , Amazon.com usw. führen Unmengen von Javascript-Code aus, ohne die Benutzererfahrung zu beeinträchtigen. Um zu verstehen, wie das geht, werden wir uns eingehend mit der Javascript-Laufzeit beschäftigen.
Javascript-Laufzeit
Javascript stellt uns verschiedene APIs zur Verfügung, um Daten vom Server abzurufen, das DOM zu manipulieren oder Funktionen mithilfe eines Timers auszuführen. Aufgrund der Single-Threaded-Natur von Javascript kann die Darstellung einer Website angehalten werden, was zu einer schlechten Leistung führt. Die Javascript-Laufzeit stellt jedoch sicher, dass dies nicht passiert. Lassen Sie uns dies anhand eines Beispiels verstehen.
Sie können sich vorstellen, was das Ergebnis des folgenden Codes sein wird:
Wird getSubTitleses nach dem Drucken gedruckt getActors? Und setTimeoutwird der Code nach dem Aufruf angehalten?
Es folgt die Ausgabe, die durch die Ausführung des obigen Codes generiert wird: –
Wie oben zu sehen ist, getSubTitleswurde zuerst gedruckt und 4 Sekunden später getActorsgedruckt. Die Funktion wartete zwar setTimeout4 Sekunden, führte aber dennoch die nachfolgende Funktion getSubTitleszuvor aus und der Code wartete nicht. Lassen Sie uns nun verstehen, was hinter den Kulissen passiert ist.
Web-APIs
Sie werden die Implementierung von Funktionen wie setTimeout, oder fetchnirgendwo im Javascript-Quellcode finden. Diese Funktionen werden vom Browser bereitgestellt und sind nicht Teil von Javascript. Die Implementierung würde für jeden Browser unterschiedlich sein.
Der Browser bietet Funktionen zum Durchführen von Netzwerkaufrufen, zum Bearbeiten des DOM, zum Verarbeiten von Audio, Videos usw. Diese Funktionen bilden die Web-APIs. Die interne Implementierung ist komplex und besteht hauptsächlich aus C++-Code. Die APIs stellen uns eine Schnittstelle zur Verfügung, die über Javascript-Code aufgerufen werden kann.
Wenn Sie eine Funktion wie aufrufen setTimeout, erkennt das Javascript, dass es sich um eine Web-API handelt. Anschließend delegiert es die Ausführung dieser Funktion an den Web-API-Container. Die Funktion setTimeoutwird in einem separaten Thread ausgeführt. Es wird nicht im Ausführungsthread von Javascript ausgeführt. Aus diesem Grund setTimeoutwird der danach geschriebene Code ausgeführt, bevor die an ihn übergebene Callback-Funktion ausgeführt wird.
Da Netzwerkaufrufe ebenfalls zeitaufwändig sind, fetchwerden die Funktionen wie z. B. in einem separaten Thread ausgeführt. Die Browser-Web-APIs verbergen den größten Teil der Komplexität vor uns. Zum Beispiel: Die interne Implementierung von fetchwürde den Aufbau einer TCP-Verbindung, das Senden der Daten und deren Analyse umfassen. Darüber hinaus würden die Rechenressourcen effizient genutzt, indem die Ausführung auf dem entsprechenden Thread geplant wird.
Das folgende GIF zeigt, was passiert, wenn Sie Web-API-Funktionen wie ausführen setTimeout.
Wie oben zu sehen ist, setTimeoutsendet die Funktion nach dem Aufruf die Rückruffunktion getActorsan die Web-APIs. Im Web-APIs-Container setTimeoutwartet die Funktion vier Sekunden. In der Zwischenzeit getSubTitleswird die nachfolgende Funktion aufgerufen.
Nun fragen Sie sich vielleicht, wie die Rückruffunktion getActorsnach Ablauf des Timers ausgeführt wird. Im nächsten Abschnitt werden wir sehen, wie Rückrufe ausgeführt werden, nachdem Web-APIs zurückgekehrt sind.
Ereigniswarteschlange
Javascript ist stark auf Callback-Funktionen angewiesen. Die Callback-Funktionen werden ausgeführt, sobald ein Ereignis eintritt. Zum Beispiel: – Nachdem wir eine Antwort vom Server erhalten haben, müssen wir die jsonDarstellung ausdrucken. Oder führen Sie eine Funktion nach einer Verzögerung von 4 Sekunden aus.
Die Javascript-Laufzeit besteht aus einer Komponente, die als Event Queue oder Callback Queue bekannt ist. Es handelt sich um eine Nachrichtenwarteschlange mit der FIFO-Reihenfolge (First In First Out). Bei den Nachrichten handelt es sich lediglich um Rückruffunktionen, deren Ausführung geplant ist.
Nehmen wir ein Beispiel, um dies zu verstehen. Im folgenden Code registrieren wir eine Rückruffunktion, wann immer ein Klickereignis auf einer Schaltfläche auftritt. Sobald der Benutzer auf die Schaltfläche klickt, onClickwird die Funktion aufgerufen. Diese Funktion ruft die Funktion timernach einer Verzögerung von 2 Sekunden auf.
Die obige Animation zeigt, was hinter den Kulissen passiert. Wir haben hier zwei Web-APIs – a) $.onund b) setTimeout. Die erste API wartet darauf, dass ein Klickereignis stattfindet. Sobald es ein Klickereignis empfängt, führt es die Funktion aus onClick. Die zweite API setTimeOutwird anschließend von der Funktion aufgerufen onClick.
Jedes Mal, wenn der Benutzer auf die Schaltfläche klickt, onClickwird die Funktion in die Ereigniswarteschlange verschoben. Ebenso wird die Funktion nach Ablauf des Timers timerin die Warteschlange verschoben. Die Ereigniswarteschlange besteht also aus allen Callback-Funktionen, die ausgeführt werden müssen. In diesem Fall onClickund die timerFunktion.
Ereignisschleife
Die Callback-Funktionen EventQueueerreichen den Ausführungsstapel von Javascript über die Ereignisschleife. Die Event-Schleife prüft kontinuierlich, ob der aktuelle Javascript-Stack leer ist. Wenn festgestellt wird, dass der Stapel leer ist, wählt es die erste Nachricht aus der Ereigniswarteschlange aus und legt sie auf dem Stapel ab.
Nehmen wir das Beispiel des vorherigen Abschnitts: Sobald die Ereignisschleife feststellt, dass der Stapel leer ist, nimmt sie die nächste Nachricht aus der Rückrufwarteschlange und führt sie aus.
Nachfolgend finden Sie einen groben Pseudocode für die Funktionsweise der Ereignisschleife: –
Sie können sich eine Ereignisschleife als eine Endlosschleife vorstellen, die den Ausführungsstapel kontinuierlich überwacht. Falls der Stapel leer ist, holt er eine Nachricht (Funktion) aus der Ereigniswarteschlange und führt sie aus.
Das folgende Diagramm zeigt die allgemeine Darstellung der Javascript-Laufzeit.
Wir haben uns die verschiedenen Komponenten in der Javascript-Laufzeit angesehen. Jetzt haben Sie eine bessere Vorstellung davon, wie Javascript unter der Haube funktioniert. Fassen wir zusammen, was wir bisher gelernt haben.
Zusammenfassung
- Javascript ist Single-Threaded und führt jeweils eine Funktion aus.
- Es nutzt Web-APIs, um komplexe Aufgaben im Hintergrund auszuführen.
- Sobald die Ausführung der Web-API abgeschlossen ist, werden die Rückruffunktionen an die Ereigniswarteschlange gesendet.
- Die Event-Schleife prüft kontinuierlich, ob der Javascript-Stack leer ist. Falls der Stapel leer ist, wählt er die Rückruffunktion aus der Ereigniswarteschlange aus und führt sie aus.
- Javascript-Interna und Laufzeit
- Wie Javascript im Browser und im Knoten funktioniert
- Eine animierte Anleitung zur Node.js-Ereignisschleife
- Was zum Teufel ist überhaupt eine Ereignisschleife?
- Asynchrones Javascript und Ereignisschleife von Grund auf

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



































