Start · Sprachen · JavaScript · Referenz · try...catch

try...catch

Anweisung

Die <code>try...catch</code>-Anweisung markiert einen Codeblock, in dem Ausnahmen abgefangen und optional anschließend Aufräumcode ausgeführt wird.

seit JavaScript ES3 / Baseline: alle Browser Kategorie: syntax

Signatur

try { tryStatements } catch (exceptionVar) { catchStatements } finally { finallyStatements }

Beschreibung

Die try...catch-Anweisung besteht aus einem try-Block und entweder einem catch-Block, einem finally-Block oder beiden. Der Code im try-Block wird zuerst ausgeführt, und falls dabei eine Ausnahme geworfen wird, wird der Code im catch-Block ausgeführt. Der Code im finally-Block wird immer ausgeführt, bevor der Kontrollfluss das gesamte Konstrukt verlässt.

Die try-Anweisung beginnt immer mit einem try-Block. Anschließend muss ein catch-Block oder ein finally-Block vorhanden sein. Es ist auch möglich, sowohl einen catch- als auch einen finally-Block zu haben. Damit ergeben sich drei Formen der try-Anweisung:

  • try...catch
  • try...finally
  • try...catch...finally

Anders als andere Konstrukte wie if oder for müssen die try-, catch- und finally-Blöcke Blöcke sein, statt einzelner Anweisungen.

Ein catch-Block enthält Anweisungen, die festlegen, was zu tun ist, wenn im try-Block eine Ausnahme geworfen wird. Wenn irgendeine Anweisung innerhalb des try-Blocks (oder in einer aus dem try-Block heraus aufgerufenen Funktion) eine Ausnahme wirft, wird die Kontrolle sofort an den catch-Block übergeben. Wird im try-Block keine Ausnahme geworfen, wird der catch-Block übersprungen.

Der finally-Block wird immer ausgeführt, bevor der Kontrollfluss das try...catch...finally-Konstrukt verlässt. Er wird immer ausgeführt, unabhängig davon, ob eine Ausnahme geworfen oder gefangen wurde.

Man kann eine oder mehrere try-Anweisungen verschachteln. Wenn eine innere try-Anweisung keinen catch-Block hat, wird stattdessen der catch-Block der umschließenden try-Anweisung verwendet.

Man kann die try-Anweisung auch verwenden, um JavaScript-Ausnahmen zu behandeln.

Catch-Binding

Wenn im try-Block eine Ausnahme geworfen wird, enthält exceptionVar (also das e in catch (e)) den Ausnahmewert. Dieses Binding kann verwendet werden, um Informationen über die geworfene Ausnahme zu erhalten. Dieses Binding ist nur im Scope des catch-Blocks verfügbar.

Es muss kein einzelner Identifier sein. Man kann ein Destructuring-Pattern verwenden, um mehrere Identifier gleichzeitig zuzuweisen.

Die durch die catch-Klausel erzeugten Bindings leben im selben Scope wie der catch-Block, daher können Variablen, die im catch-Block deklariert werden, nicht denselben Namen wie die durch die catch-Klausel erzeugten Bindings haben. (Es gibt eine Ausnahme von dieser Regel, aber sie ist eine veraltete Syntax.)

Das Exception-Binding ist beschreibbar. Beispielsweise möchte man den Ausnahmewert eventuell normalisieren, um sicherzustellen, dass es sich um ein Error-Objekt handelt.

Wenn der Ausnahmewert nicht benötigt wird, kann er zusammen mit den umschließenden Klammern weggelassen werden.

Der finally-Block

Der finally-Block enthält Anweisungen, die nach der Ausführung des try-Blocks und des/der catch-Block/-Blöcke ausgeführt werden, aber vor den Anweisungen, die auf den try...catch...finally-Block folgen. Der Kontrollfluss betritt immer den finally-Block, was auf eine der folgenden Weisen erfolgen kann:

  • Unmittelbar nachdem der Kontrollfluss den try-Block in einem try...finally-Konstrukt verlässt (entweder nach der letzten Anweisung oder einer throw-, return-, break- oder continue-Anweisung);
  • Unmittelbar nachdem der Kontrollfluss den catch-Block in einem try...catch...finally-Konstrukt verlässt;
  • Unmittelbar nachdem der Kontrollfluss den try-Block in einem try...catch...finally-Konstrukt verlässt, außer er verlässt ihn über eine throw-Anweisung (in diesem Fall betritt der Kontrollfluss zuerst den catch-Block).

Wird der finally-Block nach einer Kontrollfluss-Anweisung (return, throw, break, continue) im try- oder catch-Block betreten, wird die Wirkung dieser Anweisung aufgeschoben, bis die letzte Anweisung im finally-Block ausgeführt wurde. Wenn beispielsweise eine Ausnahme aus dem try-Block geworfen wird, wird der finally-Block auch dann noch ausgeführt, wenn es keinen catch-Block zur Behandlung der Ausnahme gibt, und die Ausnahme wird unmittelbar nach Abschluss des finally-Blocks geworfen.

Es gibt jedoch eine Ausnahme von dieser Regel: Wenn die letzte im finally-Block ausgeführte Anweisung selbst eine Kontrollfluss-Anweisung ist, überschreibt diese Anweisung die Wirkung der vorherigen (keine Verzögerung); siehe „Rückgabe aus einem finally-Block" für Beispiele. Es ist generell eine schlechte Idee, Kontrollfluss-Anweisungen (return, throw, break, continue) im finally-Block zu verwenden, da sie die Wirkung zuvor ausgeführter Kontrollfluss-Anweisungen überschreiben können, was selten beabsichtigt ist. In den meisten Fällen sollte der finally-Block für Aufräumcode reserviert sein, der die Hauptlogik nicht verändert.

Parameter

Name Typ Default Beschreibung
$tryStatements Pflicht Statements Die auszuführenden Anweisungen.
$catchStatements Statements Anweisung, die ausgeführt wird, wenn im try-Block eine Ausnahme geworfen wird.
$exceptionVar Identifier | Pattern Ein optionaler Identifier oder Pattern, der die abgefangene Ausnahme für den zugehörigen catch-Block hält. Wenn der catch-Block den Ausnahmewert nicht verwendet, kann exceptionVar zusammen mit den umschließenden Klammern weggelassen werden.
$finallyStatements Statements Anweisungen, die ausgeführt werden, bevor der Kontrollfluss das try...catch...finally-Konstrukt verlässt. Diese Anweisungen werden unabhängig davon ausgeführt, ob eine Ausnahme geworfen oder gefangen wurde.

Rückgabewert

Typ
void
Beschreibung
try...catch ist eine Anweisung (Statement) und hat keinen Rückgabewert.

Beispiele

Bedingungsloser catch-Block

try {
  throw new Error("My exception"); // generates an exception
} catch (e) {
  // statements to handle any exceptions
  logMyErrors(e); // pass exception object to error handler
}

Destructuring der Exception

try {
  throw new TypeError("oops");
} catch ({ name, message }) {
  console.log(name); // "TypeError"
  console.log(message); // "oops"
}

Exception-Binding überschreiben

try {
  throw "Oops; this is not an Error object";
} catch (e) {
  if (!(e instanceof Error)) {
    e = new Error(e);
  }
  console.error(e.message);
}

Optionales Catch-Binding

function isValidJSON(text) {
  try {
    JSON.parse(text);
    return true;
  } catch {
    return false;
  }
}

Bedingte catch-Blöcke

try {
  myRoutine(); // may throw three types of exceptions
} catch (e) {
  if (e instanceof TypeError) {
    // statements to handle TypeError exceptions
  } else if (e instanceof RangeError) {
    // statements to handle RangeError exceptions
  } else if (e instanceof EvalError) {
    // statements to handle EvalError exceptions
  } else {
    // statements to handle any unspecified exceptions
    logMyErrors(e); // pass exception object to error handler
  }
}

Erwartete Fehler abfangen, andere weiterwerfen

try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // statements to handle this very common expected error
  } else {
    throw e; // re-throw the error unchanged
  }
}

Verschachtelte try-Blöcke

try {
  try {
    throw new Error("oops");
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "finally"
// "outer" "oops"
finally outer oops

Verschachtelt mit innerem catch

try {
  try {
    throw new Error("oops");
  } catch (ex) {
    console.error("inner", ex.message);
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "inner" "oops"
// "finally"
inner oops finally

Fehler erneut werfen

try {
  try {
    throw new Error("oops");
  } catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("outer", ex.message);
}

// Logs:
// "inner" "oops"
// "finally"
// "outer" "oops"
inner oops finally outer oops

Ressourcenaufräumen mit finally

openMyFile();
try {
  // tie up a resource
  writeMyFile(theData);
} finally {
  closeMyFile(); // always close the resource
  // any uncaught exception is deferred here
}

return im try mit finally

function safeWriteMyFile() {
  openMyFile();
  try {
    return writeMyFile(theData); // function call is evaluated
  } finally {
    closeMyFile(); // always close the resource
    // return is deferred here
  }
}

Rückgabe aus einem finally-Block

function doIt() {
  const order = ["z"];
  try {
    order.push("try");
    return order.sort(); // "z" is now after "try"
  } finally {
    order.push("finally");
    return order;
  }
}
doIt();
// returns ["try", "z", "finally"], not ["finally", "try", "z"] or ["try", "z"]

finally überschreibt throw

function doIt() {
  try {
    throw "try"; // makes control flow enter the `catch` block
  } catch {
    throw "catch"; // makes control flow enter the `finally` block
  } finally {
    return "finally"; // returns "finally" instead of throwing "catch"
  }
}
doIt(); // returns "finally"

// Wichtig · Fallstricke

Nur synchrone Fehler: try...catch fängt ausschließlich Fehler ab, die synchron innerhalb des try-Blocks auftreten. Fehler in asynchronen Callbacks (setTimeout, Event-Handler) werden nicht abgefangen. Für async/await-Code funktioniert try...catch jedoch korrekt, da await ein abgelehntes Promise als synchronen Wurf behandelt.

finally überschreibt return: Ein return-Statement im finally-Block überschreibt jeden Rückgabewert aus try oder catch. Dieses Verhalten ist oft überraschend und sollte vermieden werden.

  • Performance: try...catch-Blöcke haben in modernen JS-Engines kaum messbaren Overhead, solange kein Fehler geworfen wird. Fehler zu werfen und abzufangen ist jedoch teurer als normale Kontrollfluss-Prüfungen.
  • Kein catch für Syntaxfehler: Syntaxfehler beim Parsen des Skripts werden nicht abgefangen (das Skript läuft gar nicht erst). Ausnahme: eval()-Syntaxfehler können abgefangen werden.
  • ES2019 Optional Catch Binding: Wird von allen modernen Browsern unterstützt (Chrome 66+, Firefox 58+, Safari 11.1+, Node.js 10+).

Siehe auch