What If Something Breaks?

Async errors cannot be caught by a regular try..catch because they happen outside the current call stack. Promises have their own built-in error handling mechanism.

.catch() — The Error Handler

.catch(fn) is equivalent to .then(null, fn). It catches any error that occurred anywhere in the chain above it.

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => processData(data))
  .catch(err => {
    // Catches errors from ALL the .then() steps above!
    console.error('Something failed:', err.message);
    showUserFriendlyError();
  })
  .finally(() => {
    hideLoadingSpinner(); // Always runs, success or failure
  });

Re-throwing Errors

You can catch an error, handle it partially, and then re-throw it for a higher-level handler:

fetch('/data')
  .catch(err => {
    if (err.name === 'NetworkError') {
      showOfflineMessage();
      return []; // Recover gracefully — return a default value
    }
    throw err; // Unknown error? Re-throw it!
  })
  .catch(err => logToCrashReporter(err)); // Catches re-thrown errors
Warning

A promise chain without a .catch() will silently fail. The error appears in the console as " Uncaught (in promise) " and your code just stops. Always add a .catch() at the end of your chains!