> ## Documentation Index
> Fetch the complete documentation index at: https://docs.baenninger.me/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript Engine und Performance

## Die JavaScript Engine﻿

Die JavaScript-Engine ist das Programm, das unseren Code **ausführt**. Jeder Browser hat seine eigene Engine, aber die bekannteste ist die **V8 Engine** von den Chromium-Browsern. Aber wie funktioniert die Engine?

Sie hat einen **Call Stack** und einen **Heap**. Auf dem Call Stack wird unser gesamter Code unter Verwendung des sogenannten Ausführungskontexts ausgeführt, während auf dem Heap unsere Objekte gespeichert werden.

<Frame caption="Call Stack und Heap">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-6.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=0242b2657702e299f7cef0c3e6c470a5" alt="Call Stack und Heap" width="2254" height="1710" data-path="images/content/web/image-6.png" />
</Frame>

### Kompilation vs. Interpretation﻿

Ein Prozessor versteht nur Nullen und Einsen, deshalb muss jedes einzelne Computerprogramm letztendlich in diesen Maschinencode umgewandelt werden. Dies geschieht durch Kompilierung oder Interpretation.

#### **Kompilation**﻿

Bei der Kompilierung wird der gesamte Quellcode auf einmal in Maschinencode umgewandelt. Dieser Maschinencode wird dann in eine portable Datei geschrieben, die auf jedem Computer ausgeführt werden kann. Wir haben hier also zwei Schritte:

<Frame caption="Kompilation">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-7.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=e38c3b2c3f18f4aa7682e1606ab21fdc" alt="Kompilation" width="2970" height="474" data-path="images/content/web/image-7.png" />
</Frame>

#### **Interpretation**﻿

Ein Interpreter durchläuft den Quellcode und führt ihn Zeile für Zeile aus. JavaScript war früher eine rein interpretierte Sprache, aber das Problem mit interpretierten Sprachen ist, dass sie viel, viel langsamer sind als kompilierte Sprachen.

<Frame caption="Interpretation">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-8.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=84b03598e44fe4dd1ff4849ea4766df9" alt="Interpretation" width="2748" height="474" data-path="images/content/web/image-8.png" />
</Frame>

#### **Just-In-Time (JIT) Kompilation**﻿

JavaScript verwendet jetzt eine sogenannte JIT-Kompilierung. Das ist eine Mischung aus Kompilierung und Interpretation. Dabei wird der gesamte Code auf einmal in Maschinencode umgewandelt und dann sofort ausgeführt.

<Frame caption="Javascript Engine Und Performance">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-9.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=59409d32fcb57082469af0f29e4d69e4" alt="Abbildung" width="2748" height="474" data-path="images/content/web/image-9.png" />
</Frame>

#### Die JIT Kompilation von JavaScript﻿

Wenn ein Stück JS-Code in die Engine gelangt, wird der Code zunächst **geparst**, d.h. gelesen. Beim Parsen wird der Code in eine Datenstruktur zerlegt, die **AST (Abstract Syntax Tree)** genannt wird. Dazu wird jede Codezeile in Teile zerlegt, die für die Sprache von Bedeutung sind, z. B. die Schlüsselwörter `const` oder `function`. Dann werden alle diese Teile strukturiert in dem Baum gespeichert. In diesem Schritt wird auch geprüft, ob es Syntaxfehler gibt. Der so entstandene Baum wird später verwendet, um den Maschinencode zu erzeugen.

<Frame caption="Javascript Engine Und Performance">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-13.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=7b9e2d34f4237efe16938c2b44bc1928" alt="Abbildung" width="714" height="1670" data-path="images/content/web/image-13.png" />
</Frame>

Der nächste Schritt ist **das Kompilieren**, welcher den AST in Maschinencode übersetzt. Dieser Maschinencode wird dann sofort **ausgeführt**. Die Ausführung erfolgt im **Call Stack**, dazu später mehr.

Aber wir sind noch nicht fertig, denn moderne JavaScript-Engines haben einige ziemlich clevere **Optimierungsstrategien**. Zunächst erstellen sie eine sehr unoptimierte Version des Maschinencodes, damit er so schnell wie möglich ausgeführt werden kann. Im Hintergrund wird dieser Code dann **optimiert und neu kompiliert**, während das Programm bereits ausgeführt wird. Das kann mehrmals geschehen und nach jeder Optimierung wird der nicht optimierte Code einfach gegen den neuen, optimierten Code ausgetauscht.

<Frame caption="Übersicht JIT-Compilation">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-14.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=a5ca0cffa09c8a0ae56a2facb9664a84" alt="Übersicht JIT-Compilation" width="3618" height="1876" data-path="images/content/web/image-14.png" />
</Frame>

## Die JavaScript Runtime﻿

Die häufigste JavaScript-Laufzeitumgebung ist der **Browser**. Wir können uns die JS-Runtime als eine **grosse Box oder einen grossen Container** vorstellen, der alle Dinge enthält, die wir brauchen, um JavaScript zu nutzen.

Das Herzstück jeder JavaScript-Laufzeitumgebung ist immer eine **JavaScript-Engine**. Ohne eine Engine gibt es keine Runtime und auch kein JavaScript. Die Engine allein reicht jedoch nicht aus. Damit sie richtig funktioniert, brauchen wir auch Zugang zu den **Web APIs**. Unter Web APIs versteht man alles, was mit dem **DOM**, den **Timern** oder sogar der **`console.log`** zu tun hat, die wir ständig benutzen. Web APIs sind also **Funktionalitäten**, die der Engine zur Verfügung gestellt werden, aber eigentlich nicht Teil der JavaScript-Sprache selbst sind. JavaScript erhält einfach über das globale **`window`-Objekt Zugriff** auf diese APIs.

Schliesslich enthält eine JS-Laufzeitumgebung auch eine sogenannte **Callback-Queue**. Dies ist eine Datenstruktur, die alle **Callback-Funktionen enthält**, die zur Ausführung bereit sind. Wir hängen zum Beispiel Event-Handler-Funktionen an DOM-Elemente wie eine Schaltfläche, um auf bestimmte Ereignisse zu reagieren. Diese **Eventhandler-Funktionen werden auch Callback-Funktionen genannt**.\
Wenn also ein Ereignis eintritt, z.B. ein Klick, wird die Callback-Funktion aufgerufen. Das Erste, was nach dem Ereignis passiert, ist, dass die Callback-Funktion in die **Callback-Warteschlange** gestellt wird. Wenn der Callback-Stack **leer** ist, wird die Callback-Funktion an den Stack übergeben, damit sie ausgeführt werden kann. Dies geschieht in der sogenannten **Ereignisschleife**.

<Frame caption="JavaScript Runtime">
  <img src="https://mintcdn.com/levexis-38849a2b/fK05ZPeHGTgSfJjo/images/content/web/image-15.png?fit=max&auto=format&n=fK05ZPeHGTgSfJjo&q=85&s=30e59a2b89814cfa9e9537ebc617e9e8" alt="JavaScript Runtime" width="3442" height="1832" data-path="images/content/web/image-15.png" />
</Frame>
