1.1 Grundkonzepte der Asynchronität
Asynchronität in JavaScript ermöglicht es, Aufgaben im Hintergrund auszuführen, ohne den Hauptthread zu blockieren. Das ist besonders wichtig für Aufgaben, die viel Zeit in Anspruch nehmen können, wie Netzwerk-Anfragen, Dateizugriffe und Timer. Jetzt schauen wir uns die grundlegenden Konzepte der asynchronen Programmierung in JavaScript an und geben einige Anwendungsbeispiele.
Einkernigkeit von JavaScript
JavaScript ist ein einkerniger Sprach: Das bedeutet, dass er den Code nacheinander in einem Thread ausführt. Asynchrone Operationen erlauben jedoch, Aufgaben im Hintergrund auszuführen und damit den Hauptthread für andere Aufgaben freizugeben.
Event Loop (Ereignisschleife)
Der Event Loop (Ereignisschleife) ist ein Schlüsselmechanismus, mit dem JavaScript asynchrone Aufgaben verarbeiten kann. Der Event Loop verwaltet die Nachrichtenwarteschlange (Message Queue) und die Mikrotask-Warteschlange (Microtask Queue), um die Ausführung asynchroner Operationen sicherzustellen.
- Nachrichtenwarteschlange: Enthält Aufgaben wie Ereignis-Handler, Netzwerk-Anfragen und Timer. Aufgaben aus dieser Warteschlange werden nacheinander ausgeführt.
- Mikrotask-Warteschlange: Enthält Aufgaben mit höherer Priorität im Vergleich zu den Aufgaben in der Nachrichtenwarteschlange. Beispiele sind die Fertigstellung von Promises und das Auslösen von Rückruffunktionen (Callbacks) in Mikrotasks.
Der Event Loop prüft ständig beide Warteschlangen und führt Aufgaben aus, wenn der Hauptthread frei wird.
Asynchrone Operationen
Asynchrone Operationen ermöglichen die Ausführung von Aufgaben im Hintergrund. Wichtige Beispiele für asynchrone Operationen sind:
- Timer (
setTimeout
,setInterval
) - Ereignis-Handler
- Netzwerk-Anfragen (z.B.
XMLHttpRequest
,Fetch API
) - Dateilesen/-schreiben (in Node.js)
Lass uns ein paar Beispiele für asynchrone Operationen ansehen.
1.2 Timer
Timer ermöglichen das Ausführen von Aufgaben mit einer Verzögerung oder in regelmäßigen Intervallen.
Beispiel der Verwendung von setTimeout
In diesem Beispiel setzt setTimeout
die Ausführung einer Funktion nach 2 Sekunden. Dadurch wird zuerst
Start
und End
ausgegeben, und nach 2 Sekunden folgt Executed after 2 seconds
.
console.log('Start');
setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
console.log('End');
Beispiel der Verwendung von setInterval
In diesem Beispiel führt setInterval
die Funktion jede Sekunde aus, wobei ein Zähler erhöht und dessen Wert ausgegeben wird.
Wenn der Zähler 5 erreicht, wird das Intervall mit clearInterval
beendet:
let counter = 0;
const intervalID = setInterval(() => {
counter++;
console.log(`Counter: ${counter}`);
if (counter >= 5) {
clearInterval(intervalID);
}
}, 1000);
1.3 Ereignis-Handler
Ereignis-Handler ermöglichen es, Code als Reaktion auf Benutzeraktionen oder andere Ereignisse auszuführen.
Beispiel der Verwendung von Ereignis-Handler
In diesem Beispiel wird ein click
-Ereignis-Handler zu einem Button hinzugefügt. Wenn der Benutzer den Button drückt,
wird die Nachricht Button clicked!
angezeigt:
<!DOCTYPE html>
<html>
<head>
<title>Ereignis-Handler Beispiel</title>
</head>
<body>
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
</body>
</html>
1.4 Netzwerk-Anfragen
Netzwerk-Anfragen ermöglichen das Ausführen von asynchronen HTTP-Anfragen an einen Server.
Beispiel der Verwendung von XMLHttpRequest
In diesem Beispiel wird eine asynchrone GET-Anfrage an eine API erstellt und sobald die Anfrage abgeschlossen ist, wird die Antwort in der Konsole ausgegeben:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
}
};
xhr.send();
1.5 Event Loop in Aktion
Um besser zu verstehen, wie der Event Loop funktioniert, betrachten wir folgendes Beispiel:
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 2');
});
console.log('End');
Die erwartete Ausgabe wird folgendes sein:
Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2
In diesem Beispiel werden zuerst die synchronen Operationen (console.log('Start')
und console.log('End')
) ausgeführt. Dann
werden Mikroaufgaben (Promise-Handler) ausgeführt und erst danach Aufgaben aus der Nachrichtenwarteschlange (setTimeout
).
GO TO FULL VERSION