Aufwärmen · Aufgabe 1 von 7
Zum Aufwärmen: Was bekommen Sie, wenn Sie eine async-Funktion aufrufen?
async function price() {
return 5;
}
console.log(price());// I1.3 · ca. 33 Min. · Aufbau
Nach dieser Lektion schreiben Sie Promise-Code mit async und await, der sich von oben nach unten liest, fangen seine Fehler mit try/catch/finally ab und starten unabhängige Schritte gemeinsam statt nacheinander.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
async function price() {
return 5;
}
console.log(price());Vorhersagen · Aufgabe 2 von 7
const later = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
async function main() {
console.log(await later("a", 30));
console.log(await later("b", 10));
}
main();
console.log("main called");Üben · Aufgabe 3 von 7
____ function load() {
const value = await Promise.resolve("data");
return value;
}Üben · Aufgabe 4 von 7
async function save() {
try {
await Promise.reject(new Error("disk full"));
console.log("saved");
} catch (error) {
console.log("error:", error.message);
} finally {
console.log("cleanup");
}
}
save();Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
async function isAdmin(user) {
return user === "root";
}
if (isAdmin("ada")) {
console.log("welcome, admin");
} else {
console.log("welcome, user");
}Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
step() gibt aus, wann es startet und endet, und wird nach einer Verzögerung erledigt. oneByOne() wartet auf a, dann auf b: b startet erst, nachdem a geendet hat. together() startet c und d gleichzeitig und wartet mit Promise.all, das schnellere d endet also zuerst, die Ergebnisse behalten aber ihre Reihenfolge. safely() wartet in try auf einen Schritt, der fehlschlägt: catch und finally laufen. main.js ist ein Modul, es darf daher auf oberster Ebene warten.
main.js
// A step that logs when it starts and ends, and settles after ms milliseconds.
const step = (name, ms, fail = false) =>
new Promise((resolve, reject) => {
console.log(`start ${name}`);
setTimeout(() => {
console.log(`end ${name}`);
if (fail) reject(new Error(`${name} failed`));
else resolve(name.toUpperCase());
}, ms);
});
async function oneByOne() {
const a = await step("a", 30); // b does not start until a has ended
const b = await step("b", 10);
return [a, b];
}
async function together() {
const [c, d] = await Promise.all([step("c", 30), step("d", 10)]); // both start now
return [c, d];
}
async function safely() {
try {
await step("e", 5, true);
console.log("not reached");
} catch (error) {
console.log("caught:", error.message);
} finally {
console.log("finally runs");
}
}
console.log(await oneByOne()); // top-level await: main.js is a module
console.log(await together());
await safely();
Ausführen mit
node main.jsAusgabe
start a
end a
start b
end b
[ 'A', 'B' ]
start c
start d
end d
end c
[ 'C', 'D' ]
start e
end e
caught: e failed
finally runsTab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Übung 1 von 2
profileLine(api) gibt ein Promise auf eine Zeile wie Ada (3 posts) zurück. api.user() liefert {id, name}; api.posts(id) liefert ein Array von Beiträgen. Wird api.posts abgelehnt, lautet die Zeile Ada (posts unavailable); wird api.user abgelehnt, wird profileLine mit diesem Fehler abgelehnt. Im Startcode fehlt ein await, deshalb gibt er undefined als Beitragszahl aus und fängt nie etwas ab. Beheben Sie das mit await und try/catch.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Führen Sie die Tests aus: Der erste meldet undefined Beiträge. Was ist posts ohne await?
Ein Promise hat keine length, und eine Ablehnung, die innerhalb von try nie abgewartet wird, erreicht das catch nicht.
Schreiben Sie const posts = await api.posts(user.id); innerhalb von try.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export async function profileLine(api) {
const user = await api.user();
try {
const posts = await api.posts(user.id);
return `${user.name} (${posts.length} posts)`;
} catch {
return `${user.name} (posts unavailable)`;
}
}
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
export async function profileLine(api) {
const user = await api.user();
try {
const posts = api.posts(user.id);
return `${user.name} (${posts.length} posts)`;
} catch {
return `${user.name} (posts unavailable)`;
}
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {profileLine} from './main.js';
const later = (value, fail = false) =>
new Promise((resolve, reject) => setTimeout(() => (fail ? reject(value) : resolve(value)), 5));
test('Ada mit drei Beiträgen ergibt Ada (3 posts)', async () => {
const api = {user: () => later({id: 1, name: 'Ada'}), posts: () => later(['a', 'b', 'c'])};
const got = await profileLine(api);
assert.equal(got, 'Ada (3 posts)', `profileLine gab ${got}`);
});
test('Schlagen die Beiträge fehl, ergibt es Ada (posts unavailable)', async () => {
const api = {user: () => later({id: 1, name: 'Ada'}), posts: () => later(new Error('timeout'), true)};
const got = await profileLine(api);
assert.equal(got, 'Ada (posts unavailable)', `profileLine gab ${got}`);
});
test('Ein fehlschlagender Benutzer lehnt mit demselben Fehler ab', async () => {
const api = {user: () => later(new Error('no user'), true), posts: () => later([])};
await assert.rejects(profileLine(api), {message: 'no user'}, 'profileLine sollte mit dem Benutzerfehler ablehnen');
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 2 von 2
loadAll(loaders) bekommt ein Array von Funktionen; jede gibt ein Promise zurück. Es soll ein Promise auf alle Ergebnisse in derselben Reihenfolge zurückgeben. Der Startcode wartet in einer Schleife auf jeden Loader, jeder startet also erst, wenn der vorige fertig ist. Die Ergebnisse stimmen, aber es ist langsam. Starten Sie zuerst jeden Loader und warten Sie dann gemeinsam auf alle.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Führen Sie die Tests aus: Das Protokoll zeigt start 0, end 0, start 1. Wo wartet die Schleife?
Rufen Sie zuerst jeden Loader auf: loaders.map((load) => load()) ergibt ein Array von Promises, die bereits laufen.
Warten Sie dann mit await Promise.all(…) auf alle gemeinsam; das behält ihre Reihenfolge.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export async function loadAll(loaders) {
return Promise.all(loaders.map((load) => load()));
}
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
export async function loadAll(loaders) {
const results = [];
for (const load of loaders) {
results.push(await load());
}
return results;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {loadAll} from './main.js';
// Each loader logs when it starts and ends; later ones are faster.
const makeLoaders = (log) =>
[30, 20, 10].map((ms, i) => () => {
log.push(`start ${i}`);
return new Promise((resolve) => setTimeout(() => {
log.push(`end ${i}`);
resolve(`r${i}`);
}, ms));
});
test('Die Ergebnisse kommen in der Reihenfolge der Eingabe', async () => {
const got = await loadAll(makeLoaders([]));
assert.deepEqual(got, ['r0', 'r1', 'r2'], `loadAll gab ${JSON.stringify(got)}`);
});
test('Jeder Loader startet, bevor einer von ihnen endet', async () => {
const log = [];
await loadAll(makeLoaders(log));
assert.deepEqual(log.slice(0, 3), ['start 0', 'start 1', 'start 2'], `die Reihenfolge war ${log.join(', ')}`);
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenfunction loadName() {
const name = await Promise.resolve("Ada");
return name;
}
console.log(loadName());
Was Node.js ausgibt
SyntaxError: Unexpected reserved wordWarum, und die Lösung
In einem Modul ist await ein reserviertes Wort, eine gewöhnliche Funktion, die es benutzt, lässt sich also gar nicht übersetzen, und nichts läuft. Machen Sie die Funktion async: async function loadName() { … }. Denken Sie dann daran, dass ihr Aufrufer ein Promise bekommt und ebenfalls await loadName() schreiben muss.
async function getPrice() {
return 4.5;
}
const total = getPrice() + 1;
console.log(total);
console.log(total.toFixed(2));
Was Node.js ausgibt
TypeError: total.toFixed is not a functionWarum, und die Lösung
getPrice() gibt ein Promise zurück, und + macht aus diesem Promise den Text [object Promise]. total ist also der Text "[object Promise]1", und Texte haben kein toFixed. Die erste Zeile gibt ihn ohne Fehler aus. Schreiben Sie const total = (await getPrice()) + 1;.
const wait = (ms, fail) =>
new Promise((resolve, reject) => setTimeout(() => (fail ? reject(new Error("fast one failed")) : resolve("ok")), ms));
async function both() {
const slow = wait(50, false);
const fast = wait(10, true);
try {
return [await slow, await fast];
} catch (error) {
return "handled: " + error.message;
}
}
console.log(await both());
Was Node.js ausgibt
Error: fast one failedWarum, und die Lösung
fast wird nach 10 ms abgelehnt, während die Funktion noch auf slow wartet, also behandelt noch nichts fast. Node.js wertet das als unbehandelte Ablehnung und beendet das Programm; das catch läuft nie, und „handled“ wird nie ausgegeben. Genau davor warnt MDN. Warten Sie auf beide gleichzeitig: return await Promise.all([slow, fast]); innerhalb von try.
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.