JavaScript Event Loop: So funktioniert Asynchronität | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

JavaScript Event Loop Erklaert

Zuletzt aktualisiert: 20.01.2026 um 11:25 Uhr

JavaScript Event Loop: So funktioniert Asynchronität

Der Event Loop ist das Herzstück von JavaScript's Asynchronität. Verstehen Sie Call Stack, Task Queue und Microtasks.

Die Komponenten im Überblick

Komponente Funktion
Call Stack Aktuelle Ausführung (LIFO)
Web APIs Browser-Funktionen (setTimeout, fetch, etc.)
Task Queue Callbacks von setTimeout, Events
Microtask Queue Promises, queueMicrotask
Event Loop Koordiniert alles

Visualisierung des Event Loops

┌─────────────────────────────────────────────────────────────┐
│                         BROWSER                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   ┌─────────────┐         ┌─────────────────────────┐       │
│   │  Call Stack │         │       Web APIs          │       │
│   │             │         │  - setTimeout()         │       │
│   │  function() │ ──────► │  - fetch()              │       │
│   │  function() │         │  - addEventListener()   │       │
│   │  function() │         │  - etc.                 │       │
│   └─────────────┘         └───────────┬─────────────┘       │
│          ▲                            │                      │
│          │                            ▼                      │
│          │    ┌───────────────────────────────────┐         │
│          │    │         Callback Queues           │         │
│          │    │  ┌─────────────────────────────┐  │         │
│          │    │  │  Microtask Queue (Priority) │  │         │
│          │    │  │  - Promise.then()           │  │         │
│          │    │  │  - queueMicrotask()         │  │         │
│          │    │  └─────────────────────────────┘  │         │
│   EVENT  │    │  ┌─────────────────────────────┐  │         │
│   LOOP ◄─┼────┤  │  Task Queue (Macrotasks)    │  │         │
│          │    │  │  - setTimeout()             │  │         │
│          │    │  │  - setInterval()            │  │         │
│          │    │  │  - Event Callbacks          │  │         │
│          │    │  └─────────────────────────────┘  │         │
│          │    └───────────────────────────────────┘         │
└─────────────────────────────────────────────────────────────┘

Call Stack Beispiel

function dritte() {
    console.log('Dritte Funktion');
}

function zweite() {
    dritte();
    console.log('Zweite Funktion');
}

function erste() {
    zweite();
    console.log('Erste Funktion');
}

erste();

// Call Stack Verlauf:
// 1. erste() wird gepusht
// 2. zweite() wird gepusht
// 3. dritte() wird gepusht
// 4. console.log('Dritte') - dritte() wird gepoppt
// 5. console.log('Zweite') - zweite() wird gepoppt
// 6. console.log('Erste') - erste() wird gepoppt

// Ausgabe:
// "Dritte Funktion"
// "Zweite Funktion"
// "Erste Funktion"

setTimeout und der Event Loop

console.log('1. Start');

setTimeout(() => {
    console.log('2. setTimeout Callback');
}, 0);  // 0ms Verzögerung!

console.log('3. Ende');

// Ausgabe:
// "1. Start"
// "3. Ende"
// "2. setTimeout Callback"

// Warum? setTimeout geht IMMER in die Task Queue,
// auch bei 0ms Verzögerung!

Microtasks vs. Macrotasks

console.log('1. Script Start');

// Macrotask (Task Queue)
setTimeout(() => {
    console.log('2. setTimeout');
}, 0);

// Microtask (Microtask Queue) - hat PRIORITÄT!
Promise.resolve().then(() => {
    console.log('3. Promise 1');
}).then(() => {
    console.log('4. Promise 2');
});

// Noch ein Microtask
queueMicrotask(() => {
    console.log('5. queueMicrotask');
});

console.log('6. Script Ende');

// Ausgabe:
// "1. Script Start"
// "6. Script Ende"
// "3. Promise 1"
// "5. queueMicrotask"
// "4. Promise 2"
// "2. setTimeout"

// Reihenfolge:
// 1. Synchroner Code (Call Stack)
// 2. ALLE Microtasks (Promises, queueMicrotask)
// 3. EIN Macrotask (setTimeout)
// 4. Wieder alle Microtasks
// 5. Nächster Macrotask...

Event Loop Algorithmus

// Vereinfachter Event Loop Algorithmus:

while (true) {
    // 1. Führe synchronen Code aus (bis Call Stack leer)

    // 2. Führe ALLE Microtasks aus
    while (microtaskQueue.hasItems()) {
        const task = microtaskQueue.dequeue();
        execute(task);
    }

    // 3. Rendering (falls nötig)
    if (needsRender()) {
        render();
    }

    // 4. Führe EINEN Macrotask aus (falls vorhanden)
    if (taskQueue.hasItems()) {
        const task = taskQueue.dequeue();
        execute(task);
    }

    // Zurück zu Schritt 2...
}

Komplexes Beispiel

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve()
    .then(() => {
        console.log('3');
        setTimeout(() => console.log('4'), 0);
        return Promise.resolve();
    })
    .then(() => console.log('5'));

setTimeout(() => {
    console.log('6');
    Promise.resolve().then(() => console.log('7'));
}, 0);

console.log('8');

// Ausgabe: 1, 8, 3, 5, 2, 6, 7, 4

// Erklärung:
// Synchron: 1, 8
// Microtasks: 3, 5 (Promise chain)
// Macrotask 1: 2 (erstes setTimeout)
// Macrotask 2: 6, dann Microtask 7
// Macrotask 3: 4 (setTimeout aus Promise)

Praktische Auswirkungen

// ❌ Problem: UI blockieren
function heavyCalculation() {
    for (let i = 0; i < 1000000000; i++) {
        // Lange Berechnung blockiert den Event Loop!
    }
}

heavyCalculation(); // UI friert ein

// ✅ Lösung 1: Aufteilen mit setTimeout
function heavyCalculationAsync(data, index = 0) {
    const chunkSize = 10000;
    const end = Math.min(index + chunkSize, data.length);

    for (let i = index; i < end; i++) {
        // Verarbeite Chunk
    }

    if (end < data.length) {
        setTimeout(() => heavyCalculationAsync(data, end), 0);
    }
}

// ✅ Lösung 2: Web Worker (separater Thread)
const worker = new Worker('heavy-task.js');
worker.postMessage(data);
worker.onmessage = (e) => console.log('Ergebnis:', e.data);

requestAnimationFrame

// requestAnimationFrame wird VOR dem Rendering ausgeführt
// Ideal für Animationen (60fps = alle 16.67ms)

function animate() {
    // Animation Frame - läuft vor dem Render
    element.style.transform = `translateX(${x}px)`;
    x += 1;

    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

// Reihenfolge im Event Loop:
// 1. Synchroner Code
// 2. Microtasks
// 3. requestAnimationFrame Callbacks
// 4. Render/Paint
// 5. Macrotasks

Debugging Tipps

// Eigenen Code in der Queue tracken
function logWithTiming(msg) {
    console.log(`[${performance.now().toFixed(2)}ms] ${msg}`);
}

// Prüfen welche Tasks ausstehen
console.log('Sync Code');

queueMicrotask(() => logWithTiming('Microtask'));

setTimeout(() => logWithTiming('Macrotask'), 0);

requestAnimationFrame(() => logWithTiming('Animation Frame'));

logWithTiming('Ende Sync');
⚠️ Merke: Microtasks (Promises) werden IMMER vor Macrotasks (setTimeout) ausgeführt. Eine lange Microtask-Kette kann setTimeout beliebig verzögern!

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120