Labs ICT
Pro Login

Async Error Handling

Errors in Async Code

Handling errors in asynchronous code works differently than synchronous code. A regular try/catch won't catch errors inside a callback or a rejected promise. You need different strategies for each async pattern.

// This won't catch the error!
try {
  setTimeout(() => {
    throw new Error("Oops!");
  }, 1000);
} catch (error) {
  console.log("This never runs"); // ❌
}

Catching Promise Errors

For promises, use .catch() or wrap the await in a try/catch block. Unhandled promise rejections can crash your Node.js app or show warnings in the browser.

// Using .catch()
fetchData()
  .then(data => console.log(data))
  .catch(error => console.log("Failed:", error));

// Using try/catch with async/await
async function load() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log("Failed:", error);
  }
}

The Finally Block

The finally block runs whether the async operation succeeds or fails. It's great for cleanup tasks like hiding a loading spinner.

async function loadUser() {
  showSpinner();
  try {
    const response = await fetch("/api/user");
    const user = await response.json();
    displayUser(user);
  } catch (error) {
    showError("Could not load user");
  } finally {
    hideSpinner(); // Always runs
  }
}
Try it Yourself →

Unhandled Rejection Handler

You can set up a global handler for unhandled promise rejections. This acts as a safety net for errors you didn't catch elsewhere.

// Browser
window.addEventListener("unhandledrejection", (event) => {
  console.error("Unhandled rejection:", event.reason);
});

// Node.js
process.on("unhandledRejection", (reason, promise) => {
  console.error("Unhandled rejection:", reason);
});

Summary

Always handle errors in async code. Use try/catch with async/await, .catch() with promises, and set up global handlers as a safety net. Don't let promise rejections go unhandled.