Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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:

src/fehler.js
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 (UngueltigeTransaktionFehlerHaushaltsbuchFehlerError). 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:

src/dateiSpeicher.js
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}`);
  }
}
src/index.js
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.