it-praxisportal/courses/javascript/05_callbacks_und_promises/index.html

203 lines
8.8 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JS 05: Callbacks, Event Loop &amp; Promises</title>
<link rel="stylesheet" href="../../../assets/style.css">
<style>
.promise-diagram {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin: 24px 0;
flex-wrap: wrap;
}
.state-box {
padding: 16px 20px;
border-radius: var(--radius-md);
font-weight: 700;
text-align: center;
min-width: 150px;
border: 2px solid transparent;
box-shadow: var(--shadow-sm);
}
.state-pending {
background: #fef3c7;
color: #92400e;
border-color: #f59e0b;
}
.state-fulfilled {
background: #dcfce7;
color: #166534;
border-color: #22c55e;
}
.state-rejected {
background: #ffe4e6;
color: #9f1239;
border-color: #f43f5e;
}
.diagram-arrow {
font-size: 1.5rem;
color: var(--text-muted);
font-weight: 800;
}
.analogy-box {
background: linear-gradient(135deg, #f8fafc 0%, #eef2ff 100%);
border-left: 4px solid var(--primary);
border-radius: var(--radius-sm);
padding: 18px 20px;
margin: 18px 0;
}
</style>
</head>
<body>
<div class="app-layout">
<div class="app-main">
<header>
<div class="header-container">
<div class="header-badge">🌐 JavaScript Asynchronität</div>
<h1>JS 05: Callbacks, Event Loop &amp; Promises</h1>
<p>Meistere nicht-blockierenden Code, den Event Loop und moderne Promises für robuste Web-Anwendungen.</p>
</div>
</header>
<main class="container">
<!-- Abschnitt 1: Konzept & Event Loop -->
<section class="card">
<h2>⚡ 1. Synchron vs. Asynchron &amp; Event Loop</h2>
<p>
JavaScript ist <strong>Single-Threaded</strong>. Wenn eine Aufgabe Zeit benötigt (z.&nbsp;B. Timer, Netzwerk-Aufrufe, Dateilesen), darf sie den Hauptthread nicht blockieren.
</p>
<p>
Der <strong>Event Loop</strong> sorgt dafür, dass asynchrone Callbacks in einer Warteschlange verwaltet und erst ausgeführt werden, wenn der Haupt-Callstack frei ist.
</p>
<div class="analogy-box">
<h3>🍔 Die Restaurant-Pieper-Analogie</h3>
<p>
Bestellst du in einem Restaurant dein Essen, musst du <em>nicht</em> starr an der Kasse stehen bleiben. Du erhältst sofort einen <strong>Bestell-Pieper (ein Promise im Zustand <code>pending</code>)</strong>. Du setzt dich entspannt an deinen Tisch (der Event Loop verarbeitet andere Dinge).
</p>
<p style="margin-bottom: 0;">
Ist dein Menü fertig, vibriert der Pieper (<strong><code>resolve</code> &rarr; <code>fulfilled</code></strong>). Brennt die Küche, blinkt er rot (<strong><code>reject</code> &rarr; <code>rejected</code></strong>).
</p>
</div>
</section>
<!-- Abschnitt 2: Was ist ein Promise & Zustandsdiagramm -->
<section class="card">
<h2>📊 2. Das Promise-Zustandsdiagramm</h2>
<p>
Ein <code>Promise</code> ist ein Stellvertreter-Objekt für einen zukünftigen Wert. Es befindet sich immer in genau einem von drei Zuständen:
</p>
<div class="promise-diagram">
<div class="state-box state-pending">
⏳ pending<br>
<small>(wartend / schwebend)</small>
</div>
<div style="display: flex; flex-direction: column; gap: 14px; align-items: center;">
<div style="display: flex; align-items: center; gap: 8px;">
<span class="diagram-arrow">&rarr;</span>
<span style="font-size: 0.85rem; font-weight: 700; color: #166534;">resolve(wert)</span>
<span class="diagram-arrow">&rarr;</span>
<div class="state-box state-fulfilled">
✅ fulfilled<br>
<small>.then(wert => ...)</small>
</div>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<span class="diagram-arrow">&rarr;</span>
<span style="font-size: 0.85rem; font-weight: 700; color: #9f1239;">reject(error)</span>
<span class="diagram-arrow">&rarr;</span>
<div class="state-box state-rejected">
❌ rejected<br>
<small>.catch(err => ...)</small>
</div>
</div>
</div>
</div>
</section>
<!-- Abschnitt 3: Code-Muster & Chaining -->
<section class="card">
<h2>🛠️ 3. Eigene Promises &amp; Chaining</h2>
<p>Ein Promise wird mit <code>new Promise((resolve, reject) => { ... })</code> erzeugt:</p>
<pre><code>// 1. Promise definieren
function ladeDaten(id) {
return new Promise((resolve, reject) => {
if (id > 0) {
setTimeout(() => resolve({ id: id, status: "ok" }), 100);
} else {
reject(new Error("ID muss positiv sein"));
}
});
}
// 2. Promise verketten (Chaining)
ladeDaten(42)
.then(daten => {
console.log("Geladen:", daten);
return daten.id * 2;
})
.then(verdoppelt => console.log("Verdoppelt:", verdoppelt))
.catch(err => console.error("Fehler:", err.message))
.finally(() => console.log("Vorgang abgeschlossen."));</code></pre>
<h3 style="margin-top: 24px;">🚀 Parallelisierung mit <code>Promise.all()</code></h3>
<pre><code>// Lädt quelleA und quelleB parallel und wartet auf beide
Promise.all([quelleA, quelleB])
.then(([resA, resB]) => console.log("Beide fertig:", resA, resB))
.catch(err => console.error("Mindestens eine Quelle schlug fehl:", err));</code></pre>
</section>
<!-- Abschnitt 4: Aufgaben & Checkliste -->
<section class="card">
<h2>🎯 Aufgaben &amp; Checkliste</h2>
<div class="task-item">
<input type="checkbox" class="task-checkbox" id="t1">
<label class="task-label" for="t1">
<strong>TODO 1:</strong> <code>verzoegereAusfuehrung(ms, rueckgabeWert)</code> mit <code>setTimeout</code> &amp; <code>resolve</code> bauen.
</label>
</div>
<div class="task-item">
<input type="checkbox" class="task-checkbox" id="t2">
<label class="task-label" for="t2">
<strong>TODO 2:</strong> <code>pruefeZahlGroesserNull(zahl)</code> mit <code>resolve</code> bei &gt; 0 bzw. <code>reject</code> bei &lt;= 0 schreiben.
</label>
</div>
<div class="task-item">
<input type="checkbox" class="task-checkbox" id="t3">
<label class="task-label" for="t3">
<strong>TODO 3:</strong> <code>ladeBenutzerProfil(userId)</code> simulieren und Profil-Objekt auflösen.
</label>
</div>
<div class="task-item">
<input type="checkbox" class="task-checkbox" id="t4">
<label class="task-label" for="t4">
<strong>TODO 4:</strong> <code>ladeAlleDatenQuellen(quelleA, quelleB)</code> mittels <code>Promise.all()</code> parallel aggregieren.
</label>
</div>
<!-- Lösungstipps Collapsible -->
<details style="margin-top: 20px; padding: 14px; background: #f8fafc; border: 1px solid var(--border-color); border-radius: var(--radius-sm);">
<summary style="cursor: pointer; font-weight: 700; color: var(--primary);">💡 Lösungstipps &amp; Hilfestellung</summary>
<ul style="margin-top: 10px; margin-left: 20px; font-size: 0.92rem; color: var(--text-body);">
<li>Nutze <code>return new Promise((resolve, reject) => { ... });</code>.</li>
<li>Innerhalb des Executors rufst du <code>resolve(wert)</code> bei Erfolg oder <code>reject(new Error("..."))</code> bei Fehlern auf.</li>
<li><code>Promise.all</code> nimmt ein Array entgegen: <code>Promise.all([quelleA, quelleB])</code>.</li>
</ul>
</details>
<div style="margin-top: 24px; display: flex; gap: 12px; flex-wrap: wrap;">
<a href="../../../workspace.html?course=javascript&track=track_2_async_und_apis&chapter=05_callbacks_und_promises" class="btn" style="background: #eab308; color: #000; font-weight: 700; text-decoration: none; padding: 10px 20px; border-radius: 6px;">💻 In Web-IDE öffnen &rarr;</a>
<a href="../06_async_await_und_fetch/index.html" class="btn" style="background: #4f46e5; color: #fff; font-weight: 600; text-decoration: none; padding: 10px 20px; border-radius: 6px;">Weiter zu Modul 06 &rarr;</a>
</div>
</section>
</main>
</div>
</div>
</body>
</html>