Fehlerbehandlung in JavaScript
Fehlerbehandlung in JavaScript
~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Zum Abschluss von Phase 4 bauen wir eine robuste Fehlerbehandlung für unser gesamtes Datei-System – inklusive eigener, aussagekräftiger Error-Klassen für unser Haushaltsbuch.
try, catch und finally
try {
const daten = JSON.parse('{ ungueltiges json');
console.log(daten);
} catch (fehler) {
console.error('Fehler beim Parsen:', fehler.message);
} finally {
console.log('Läuft IMMER - egal ob Fehler oder nicht'); // z. B. für Aufräumarbeiten
}try/catch mit async/await
Der große praktische Vorteil von async/await gegenüber .then()/.catch()-Ketten: Fehlerbehandlung nutzt DASSELBE try/catch wie synchroner Code, statt eine separate .catch()-Syntax zu brauchen:
async function ladeTransaktionenSicher(pfad) {
try {
const inhalt = await readFile(pfad, 'utf-8');
return JSON.parse(inhalt);
} catch (fehler) {
console.error(`Konnte ${pfad} nicht laden:`, fehler.message);
return []; // sinnvoller Fallback statt Absturz
}
}Eigene Error-Klassen
Die eingebaute Error-Klasse lässt sich erweitern, um AUSSAGEKRÄFTIGERE, spezifischere Fehlertypen für unser Haushaltsbuch zu modellieren:
export class HaushaltsbuchFehler extends Error {
constructor(nachricht) {
super(nachricht);
this.name = 'HaushaltsbuchFehler'; // erscheint in Stack Traces statt 'Error'
}
}
export class UngueltigeTransaktionFehler extends HaushaltsbuchFehler {
constructor(grund) {
super(`Ungültige Transaktion: ${grund}`);
this.name = 'UngueltigeTransaktionFehler';
}
}
export class DateiNichtGefundenFehler extends HaushaltsbuchFehler {
constructor(pfad) {
super(`Datei nicht gefunden: ${pfad}`);
this.name = 'DateiNichtGefundenFehler';
this.pfad = pfad; // zusätzliche, spezifische Information am Error
}
}Fehlertypen im catch-Block unterscheiden
import { UngueltigeTransaktionFehler, DateiNichtGefundenFehler } from './fehler.js';
function validiereTransaktion(transaktion) {
if (typeof transaktion.betrag !== 'number' || Number.isNaN(transaktion.betrag)) {
throw new UngueltigeTransaktionFehler('Betrag muss eine gültige Zahl sein');
}
if (!transaktion.beschreibung) {
throw new UngueltigeTransaktionFehler('Beschreibung fehlt');
}
}
try {
validiereTransaktion({ beschreibung: 'Miete', betrag: 'nicht-numerisch' });
} catch (fehler) {
if (fehler instanceof UngueltigeTransaktionFehler) {
console.error('Validierungsfehler:', fehler.message);
} else if (fehler instanceof DateiNichtGefundenFehler) {
console.error('Datei-Problem:', fehler.pfad);
} else {
throw fehler; // unbekannter Fehlertyp - erneut werfen, statt ihn zu verschlucken!
}
}Achtung: instanceof nutzt die Prototypenkette aus Kapitel 20 – DESHALB funktioniert die Unterscheidung zuverlässig, auch über mehrere Vererbungsebenen (UngueltigeTransaktionFehler → HaushaltsbuchFehler → Error). Einen unbekannten Fehlertyp im catch-Block STILL zu ignorieren, statt ihn erneut zu werfen, versteckt echte Bugs.
Das komplette Datei-Speichersystem
Damit fügen wir alles aus Phase 4 zu einem robusten Speichersystem für unser Haushaltsbuch zusammen:
import { readFile, writeFile } from 'node:fs/promises';
import { DateiNichtGefundenFehler, HaushaltsbuchFehler } from './fehler.js';
export async function ladeTransaktionen(pfad) {
try {
const inhalt = await readFile(pfad, 'utf-8');
return JSON.parse(inhalt);
} catch (fehler) {
if (fehler.code === 'ENOENT') {
throw new DateiNichtGefundenFehler(pfad);
}
throw new HaushaltsbuchFehler(`Konnte ${pfad} nicht lesen: ${fehler.message}`);
}
}
export async function speichereTransaktionen(pfad, transaktionen) {
try {
await writeFile(pfad, JSON.stringify(transaktionen, null, 2), 'utf-8');
} catch (fehler) {
throw new HaushaltsbuchFehler(`Konnte ${pfad} nicht schreiben: ${fehler.message}`);
}
}import { ladeTransaktionen, speichereTransaktionen } from './dateiSpeicher.js';
import { DateiNichtGefundenFehler } from './fehler.js';
try {
const transaktionen = await ladeTransaktionen('daten/transaktionen.json');
console.log(`${transaktionen.length} Transaktionen geladen`);
transaktionen.push({ beschreibung: 'Kino', betrag: -18, kategorie: 'Freizeit' });
await speichereTransaktionen('daten/transaktionen.json', transaktionen);
console.log('Gespeichert!');
} catch (fehler) {
if (fehler instanceof DateiNichtGefundenFehler) {
console.log('Noch keine Datei vorhanden, starte mit leerem Haushaltsbuch.');
} else {
console.error('Unerwarteter Fehler:', fehler.message);
}
}Damit ist Phase 4 (Asynchronität) abgeschlossen! In Phase 5 runden wir das Projekt mit JSON-Persistenz-Vertiefung, automatisierten Tests und einer abschließenden Best-Practices-Zusammenfassung ab.