Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

JavaScript und Aynchronität

Weil ein Browser bereits auf dem Betriebssystem als Applikation läuft, steht den Teilen in JavaScript nur ein Thread zur Verfügung. Ein Thread ist eine Ressource, welche das Betriebssystem einer Applikation für die Ausführung von Rechenoperationen bereit stellt. Hat man nur 1 solchen Thread, können keine Rechenoperationen gleichzeitig behandelt werden. Der Browser kümmert sich aber nebst dem Ausführen von JavaScript auch noch um die Darstellung der Seite mit HTML oder CSS. Wenn du jetzt also bspw. die ersten 100 Zahlen der Fibonacci Folge berechnen willst, würde die Webseite während dieser Zeit "einfrieren" und keine Interaktionen vom Benutzer mehr entgegen nehmen. Dieses "Problem"wird so gelöst, dass der Browser angewiesen wird (mit JavaScript), dass er aufwändigere Operationen nachlagert ausführt. Du weisst dann nicht genau, wann dein Stück Code effektiv ausgeführt wird. Dieses "asynchrone" Verhalten führt im Umgang mit JavaScript zu einer höheren Komplexität.

Du kannst dir so vorstellen, wie wenn du jemanden bittest, dir einen Kaffee zu besorgen. Während der Kaffee "hoffentlich" organisiert wird, arbeitest du weiter. Wenn er dann da ist, wirst du den Kaffee trinken wollen. Die Aktion "Kaffee trinken" definierst du zwar schon bei der Bestellung des Kaffees (das ist deine Absicht), führst sie aber erst aus, wenn der Kaffee da ist.

In JavaScript wird dies so gelöst, indem eine Funktion eine andere Funktion entgegen nimmt. Die Funktion "Kaffee trinken" wird der Funktion "Kaffee bestellen" mitgegeben. Wenn der Kaffee dann da ist, wird er getrunken. Zeitpunkt und Detail der Ausführung wird in der Methode "Kaffee bestellen" definiert, der konkrete Ablauf von "Kaffee trinken" in der Funktion, die übergeben wird.

Unter w3schools Callbacks findest du ebenfalls ein Code Beispiel dazu. Sicher findest du auch auf YouTube Erklär-Videos zu Callbacks.

Die Syntax sieht wie folgt aus:

function functionWithCallback(callback) {
  console.log("Funktion mit Callback wird ausgeführt");
  callback();
}

function callbackFunction() {
  console.log("Callback-Funktion wird ausgeführt");
}

functionWithCallback(callbackFunction);

Die Funktion functionWithCallback nimmt als Parameter eine Funktion entgegen, welche dann ausgeführt wird. Mittels () siehst du, dass es eine Funktion ist. Inhaltlich weiss die Methode nicht, was sie ausführt, bestimmt aber den Zeitpunkt.

Die Funktion callbackFunction ist die Funktion selbst. Ein Beispiel mit dem Kaffee trinken können wir erweitern, dass die Funktion "Kaffee bestellen" der Funktion "Kaffee trinken" auch noch mitgibt, welchen Kaffee genau eigentlich bestellt wurde.

function orderCoffee(callback) {
  console.log("Kaffee wird bestellt...");
  console.log("Kaffee ist da!");
  callback("Milchkaffee");
}

function drinkCoffee(coffeeType) {
  console.log(`Kaffee wird getrunken: ${coffeeType} ☕️`);
}

orderCoffee(drinkCoffee);

Die Funktion "drinkCoffee" verlangt also ebenfalls einen Parameter, den sie nutzen will. Sie weiss nicht "was" dort mitkommt. Die "orderCoffee" Funktion muss sich nun also darum kümmern und übergibt den Typ beim Aufruf des Callbacks.

Wieso macht das so nicht viel Sinn? Der Aufruf von "callback" ist aktuell relativ synchron, da Zeile für Zeile abgearbeitet wird. Stell dir vor, es braucht lange bis die Aktion durch ist. In einem technischen Sinne beispielsweise, weil die Aufgabe über einen entfernten Server erfolgt oder eine lang dauernde Datebankabfrage erfolgt. Du kannst so was mit einem "setTimeout()" simulieren.

function orderCoffee(callback) {
  console.log("Kaffee wird bestellt...");
  setTimeout(() => {
    console.log("Kaffee ist da!");
    callback("Milchkaffee");
  }, 2000);
}

Wir warten nun 2 Sekunden, bis es weiter geht.

Die Syntax wie oben kann zu Problemen mit this führen und ist etwas mühsam, wenn wir das oft brauchen. Darum kennt JavaScript die "Arrow" Funktion.

Arrow functions

Anstelle von

orderCoffee(drinkCoffee) übergeben wir den Inhalt von "drinkCoffee" direkt mit der Arrow Syntax

function orderCoffee(callback) {
  console.log("Kaffee wird bestellt...");
  setTimeout(() => {
    console.log("Kaffee ist da!");
    callback("Milchkaffee");
  }, 2000);
}

orderCoffee((coffeeType) => {
  console.log(`Kaffee wird getrunken: ${coffeeType} ☕️`);
});

die ganze drinkCoffee Funktion ist nicht mehr nötig und wird direkt geschrieben. Du musst das nicht und kannst immer noch innerhalb des Arrow Bodys {} eine andere Funktion aufrufen.