Start · Sprachen · JavaScript · Referenz · Promise.prototype.finally()

Promise.prototype.finally()

Methode

Registriert eine Funktion, die ausgeführt wird, sobald das Promise abgeschlossen ist – egal ob erfüllt oder abgelehnt – und gibt ein neues Promise zurück.

seit JavaScript ES2018 Kategorie: method-property

Signatur

Promise.prototype.finally(onFinally)

Beschreibung

Mit finally() registrierst du einen Callback, der immer läuft, sobald ein Promise abgeschlossen ist, ob erfolgreich oder mit Fehler. Er eignet sich für Aufräumarbeiten, die in beiden Fällen nötig sind: einen Ladeindikator ausblenden, eine Verbindung schließen, einen Button wieder aktivieren oder eine Sperre freigeben. So musst du denselben Code nicht in then() und catch() doppelt schreiben.

Der Callback bekommt keine Argumente. Er erfährt also weder den Ergebniswert noch den Ablehnungsgrund. Das ist so gewollt: finally() soll unabhängig vom Ergebnis sein. Das zurückgegebene Promise reicht den ursprünglichen Zustand weiter. Ein erfüllter Wert bzw. ein Fehler geht unverändert an die nächsten Glieder der Kette. Was der Callback zurückgibt, wird normalerweise ignoriert.

Es gibt zwei Ausnahmen: Wirft der Callback einen Fehler oder gibt er ein abgelehntes Promise zurück, wird das neue Promise mit diesem Grund abgelehnt. Gibt der Callback ein Promise zurück, wartet die Kette, bis es abgeschlossen ist, und übernimmt danach den ursprünglichen Wert. In async-Funktionen entspricht finally() dem finally-Block von try...catch...finally.

Parameter

Name Typ Default Beschreibung
$onFinally Function | undefined Funktion, die aufgerufen wird, wenn das Promise abgeschlossen ist. Sie erhält keine Argumente. Ist onFinally keine Funktion, wird der Wert intern durch eine Durchreich-Funktion ersetzt. Das Verhalten entspricht dann then(onFinally, onFinally).

Rückgabewert

Typ
Promise<T>
Beschreibung
Ein neues Promise, das sich im Normalfall genau wie das ursprüngliche Promise verhält: mit demselben Wert erfüllt oder mit demselben Grund abgelehnt. Nur wenn onFinally einen Fehler wirft oder ein abgelehntes Promise zurückgibt, wird es mit diesem neuen Grund abgelehnt.

Beispiele

Ladeindikator nach fetch immer ausblenden

const loadUser = (id) => {
  const spinner = document.querySelector('#spinner');
  spinner.hidden = false;

  return fetch(`/api/users/${id}`)
    .then((res) => {
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return res.json();
    })
    .catch((err) => {
      console.error('Laden fehlgeschlagen:', err.message);
      return null;
    })
    .finally(() => {
      // läuft bei Erfolg UND bei Fehler
      spinner.hidden = true;
      console.log('Spinner ausgeblendet');
    });
};

loadUser(42).then((user) => console.log('Ergebnis:', user));
Spinner ausgeblendet Ergebnis: { id: 42, name: "..." } // bzw. null bei Fehler

Wert und Fehler werden unverändert durchgereicht

Promise.resolve('Daten')
  .finally(() => 'wird ignoriert')
  .then((value) => console.log('Wert:', value));

Promise.reject(new Error('Kaputt'))
  .finally(() => console.log('Aufräumen'))
  .catch((err) => console.log('Fehler:', err.message));
Aufräumen Wert: Daten Fehler: Kaputt

Fehler im finally-Callback überschreibt das Ergebnis

Promise.resolve(1)
  .finally(() => {
    throw new Error('Cleanup fehlgeschlagen');
  })
  .then((v) => console.log('Wert:', v))
  .catch((err) => console.log('Abgelehnt:', err.message));
Abgelehnt: Cleanup fehlgeschlagen

Asynchrones Aufräumen – die Kette wartet

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const withConnection = async () => {
  const conn = { close: async () => { await sleep(100); console.log('Verbindung geschlossen'); } };
  return Promise.resolve('Abfrage-Ergebnis')
    .finally(() => conn.close()); // Kette wartet auf close()
};

const result = await withConnection();
console.log(result);
Verbindung geschlossen Abfrage-Ergebnis

// Wichtig · Fallstricke

  • Keine Argumente: Der Callback erhält weder den Wert noch den Fehler. Brauchst du einen davon, verwende then() bzw. catch().
  • Fehler werden nicht abgefangen: finally() behandelt keine Ablehnung. Ohne ein folgendes catch() bleibt eine Ablehnung unbehandelt und löst unhandledrejection aus.
  • Rückgabewert wird ignoriert: return im Callback ändert das Ergebnis nicht. Anders ist es bei throw oder einem abgelehnten Promise: Beides überschreibt den ursprünglichen Wert bzw. Fehler. Der ursprüngliche Fehler geht dabei verloren.
  • Unterschied zu then(f, f): Dort ersetzt der Rückgabewert von f das Ergebnis, und ein Fehler gilt nach dem Aufruf als behandelt. Bei finally() ist beides nicht so.
  • Immer asynchron: Auch bei einem bereits abgeschlossenen Promise läuft der Callback erst als Microtask, nie synchron.
  • Kompatibilität: Seit ES2018 in allen modernen Browsern (Chrome 63, Firefox 58, Safari 11.1, Edge 18) und in Node.js ab Version 10. Der Internet Explorer unterstützt die Methode nicht; dort ist ein Polyfill nötig, z. B. aus core-js.