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

Callbacks und Promises in JavaScript

Callbacks und Promises in JavaScript

~15 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Mit dem Event-Loop-Wissen aus Kapitel 23 bauen wir jetzt die erste ECHTE asynchrone Operation unseres Haushaltsbuchs: Transaktionen aus einer Datei laden.

Das klassische Callback-Pattern

Vor Promises war der einzige Weg, auf ein asynchrones Ergebnis zu reagieren, eine Callback-Funktion zu übergeben, die AUFGERUFEN wird, sobald das Ergebnis vorliegt:

import { readFile } from 'node:fs';

readFile('transaktionen.json', 'utf-8', (fehler, inhalt) => {
  if (fehler) {
    console.error('Fehler beim Lesen:', fehler.message);
    return;
  }
  console.log('Inhalt:', inhalt);
});

console.log('Diese Zeile läuft VOR dem Datei-Inhalt!'); // Call Stack aus Kapitel 23 in Aktion

Callback Hell: das Problem verschachtelter Callbacks

Sobald mehrere asynchrone Schritte NACHEINANDER ausgeführt werden müssen, führt das Callback-Pattern zu tief verschachteltem, schwer lesbarem Code:

ladeTransaktionen((fehler, transaktionen) => {
  if (fehler) return console.error(fehler);
  berechneSaldo(transaktionen, (fehler, saldo) => {
    if (fehler) return console.error(fehler);
    speichereSaldo(saldo, (fehler) => {
      if (fehler) return console.error(fehler);
      console.log('Fertig! Saldo gespeichert:', saldo);
      // ... und so weiter, immer weiter nach rechts eingerückt
    });
  });
});

Achtung: Dieses "Pfeilspitzen"-Muster ("Pyramid of Doom") ist der Hauptgrund, warum Promises eingeführt wurden – genau dieses Verschachtelungsproblem lösen sie.

Promises: ein Versprechen auf einen zukünftigen Wert

Ein Promise repräsentiert einen Wert, der JETZT noch nicht, aber IRGENDWANN verfügbar sein wird. Ein Promise befindet sich immer in genau einem von drei Zuständen: pending (ausstehend), fulfilled (erfüllt) oder rejected (fehlgeschlagen).

function ladeTransaktionenPromise() {
  return new Promise((resolve, reject) => {
    readFile('transaktionen.json', 'utf-8', (fehler, inhalt) => {
      if (fehler) {
        reject(fehler); // Promise wird 'rejected'
      } else {
        resolve(JSON.parse(inhalt)); // Promise wird 'fulfilled' mit diesem Wert
      }
    });
  });
}

ladeTransaktionenPromise()
  .then(transaktionen => console.log('Geladen:', transaktionen.length))
  .catch(fehler => console.error('Fehler:', fehler.message));

Promises verketten: das Ende der Callback Hell

.then() gibt selbst wieder ein Promise zurück – dadurch lassen sich mehrere asynchrone Schritte FLACH statt verschachtelt aneinanderreihen, das identische Beispiel von oben, jetzt lesbar:

ladeTransaktionenPromise()
  .then(transaktionen => berechneSaldoPromise(transaktionen))
  .then(saldo => speichereSaldoPromise(saldo))
  .then(() => console.log('Fertig!'))
  .catch(fehler => console.error('Irgendein Schritt ist fehlgeschlagen:', fehler.message));

Mehrere Promises parallel: Promise.all

Sollen mehrere UNABHÄNGIGE asynchrone Operationen PARALLEL laufen (nicht nacheinander), ist Promise.all() das richtige Werkzeug:

Promise.all([
  ladeTransaktionenPromise('januar.json'),
  ladeTransaktionenPromise('februar.json'),
  ladeTransaktionenPromise('maerz.json'),
])
  .then(([januar, februar, maerz]) => {
    console.log('Alle drei Monate geladen:', januar.length + februar.length + maerz.length);
  })
  .catch(fehler => console.error('Mindestens einer der drei ist fehlgeschlagen:', fehler.message));

Achtung: Promise.all() schlägt SOFORT komplett fehl, sobald AUCH NUR EINES der übergebenen Promises fehlschlägt ("fail fast"). Sollen ALLE Ergebnisse eingesammelt werden, unabhängig davon, ob einzelne fehlschlagen, ist Promise.allSettled() die passendere Alternative.

Promises sind bereits deutlich lesbarer als verschachtelte Callbacks – in Kapitel 25 lernen wir mit async/await eine noch elegantere Syntax für GENAU dasselbe Konzept kennen.