Kurz: async/await ist eine Schreibweise, mit der asynchroner Code wie normaler, nacheinander ablaufender Code aussieht. Sie baut auf Promises auf.
Teil des Kurses JavaScript
Kapitel 26 von 40 im Kurs JavaScript. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.
async/await ist eine Schreibweise, mit der asynchroner Code wie normaler, nacheinander ablaufender Code aussieht. Sie baut auf Promises auf.
Grundidee
- Eine
async-Funktion liefert immer ein Promise. - Mit
awaitwartet die Funktion auf ein Promise, ohne den Rest des Programms zu blockieren.
const warte = (ms, wert) => new Promise(r => setTimeout(() => r(wert), ms));
async function ablauf() {
console.log("start");
const a = await warte(50, "A");
console.log("erhalten:", a);
const b = await warte(10, "B");
return a + b;
}
ablauf().then(erg => console.log("Ergebnis:", erg));
console.log("läuft schon weiter");Ausgabe:
start
läuft schon weiter
erhalten: A
Ergebnis: ABFehler abfangen
Bei await nutzt du ganz normal try/catch:
async function laden() {
try {
const r = await Promise.reject(new Error("Server nicht erreichbar"));
console.log(r);
} catch (e) {
console.log("Fehler:", e.message);
} finally {
console.log("fertig");
}
}
laden();Ausgabe:
Fehler: Server nicht erreichbar
fertigNacheinander oder parallel?
Mehrere await hintereinander laufen nacheinander. Unabhängige Aufgaben startest du besser gleichzeitig:
const task = (name, ms) => new Promise(r => setTimeout(() => r(name), ms));
async function main() {
let t0 = Date.now();
await task("a", 100);
await task("b", 100);
console.log("nacheinander ~200 ms:", Date.now() - t0 >= 190);
t0 = Date.now();
const [x, y] = await Promise.all([task("a", 100), task("b", 100)]);
console.log("parallel ~100 ms:", Date.now() - t0 < 190, x, y);
}
main();Ausgabe:
nacheinander ~200 ms: true
parallel ~100 ms: true a bAchtung
awaitinforEachfunktioniert nicht wie erwartet, weilforEachnicht wartet. Nutzefor...ofmitawaitoderPromise.allmitmap.
const sleep = ms => new Promise(r => setTimeout(r, ms));
(async () => {
for (const x of [1, 2, 3]) { // nacheinander
await sleep(5);
console.log("seq", x);
}
const alle = await Promise.all([1, 2, 3].map(async x => { await sleep(5); return x * 2; }));
console.log(alle);
})();Ausgabe:
seq 1
seq 2
seq 3
[ 2, 4, 6 ]Daten aus dem Netz: fetch
fetch() holt Daten per HTTP und liefert ein Promise. Es funktioniert im Browser und in Node.js (ab Version 18):
async function ladeNutzer(id) {
const antwort = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!antwort.ok) {
throw new Error(`HTTP-Fehler ${antwort.status}`);
}
const daten = await antwort.json();
return daten.name;
}
ladeNutzer(1)
.then(name => console.log(name))
.catch(fehler => console.log("Fehler:", fehler.message));Wichtig: fetch löst nur bei Netzwerkfehlern einen Fehler aus. Eine Antwort mit Status 404 oder 500 ist trotzdem eine “erfolgreiche” Antwort, daher prüfst du antwort.ok selbst.
Daten senden
const antwort = await fetch("/api/nachrichten", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: "Hallo" }),
});
const ergebnis = await antwort.json();| Antwort-Methode | liefert |
|---|---|
antwort.json() | geparstes JSON |
antwort.text() | Text |
antwort.blob() | Binärdaten (Bilder) |
antwort.status, antwort.ok | Statuscode, Erfolg (200 bis 299) |
Abbrechen und Zeitlimit
const warte = ms => new Promise((_, rej) => setTimeout(() => rej(new Error("Zeitüberschreitung")), ms));
const langsam = new Promise(r => setTimeout(() => r("fertig"), 500));
Promise.race([langsam, warte(50)])
.then(console.log)
.catch(e => console.log(e.message));
const abbruch = new AbortController();
abbruch.signal.addEventListener("abort", () => console.log("abgebrochen:", abbruch.signal.aborted));
abbruch.abort();Ausgabe:
abgebrochen: true
ZeitüberschreitungBei fetch übergibst du { signal: controller.signal }, um eine Anfrage abzubrechen. AbortSignal.timeout(5000) bricht automatisch nach 5 Sekunden ab.
Top-Level await
In ES-Modulen darfst du await auch außerhalb einer Funktion verwenden:
// in einer .mjs-Datei oder <script type="module">
const daten = await fetch("/daten.json").then(r => r.json());Merke
asyncmacht eine Funktion zu einer, die ein Promise liefertawaitwartet auf ein Promise, ohne das Programm zu blockieren- Fehler mit
try/catchabfangen - Unabhängiges mit
Promise.allparallel ausführen fetchwirft bei 404/500 nicht:antwort.okprüfen
Übungsaufgabe
Schreibe eine async-Funktion, die drei Wartezeiten parallel startet, mit Promise.all wartet und die Gesamtdauer ausgibt. Baue einen Fehlerfall mit try/catch ein.
Quiz zur Selbstkontrolle
Was liefert eine async-Funktion zurück?
- Immer ein Promise (richtig)
- Immer undefined
- Das Ergebnis direkt
- Ein Array
Löst fetch bei einer 404-Antwort einen Fehler aus?
- Nein, du musst response.ok prüfen (richtig)
- Ja, immer
- Nur in Node.js
- Nur bei POST
Wie startest du zwei unabhängige Aufgaben parallel?
- await Promise.all([a(), b()]) (richtig)
- await a(); await b();
- a().then(b)
- while(true) { a(); b(); }
Weiter im Kurs
Zurück: Asynchron: Callbacks und Promises
Weiter: Timer und die Event Loop
Alle Kapitel: JavaScript im Überblick