Logo
READLEARNKNOWCONNECT
Back to Lessons

    Page

  • - Why Async Error Handling Matters
  • - Errors in Promises
  • - Async/Await with try...catch
  • - Handling Multiple Async Operations
  • - Retrying Failed Requests
  • - Handling API Errors Gracefully
  • - Mini Challenge

26. Error Handling in Async JavaScript

Level: IntermediateDuration: 40m

Why Async Error Handling Matters

Modern web apps rely heavily on asynchronous operations: API calls, timers, file reading, and more. Handling errors correctly ensures your app remains reliable and users get meaningful feedback instead of broken experiences.

Errors in Promises

Promises represent future results. Errors in promises are caught with `.catch()`.

javascript
fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    if (!response.ok) throw new Error('Network response was not ok');
    return response.json();
  })
  .then(data => console.log(data))
  .catch(err => console.error('Fetch failed:', err.message));

Async/Await with try...catch

Async/await makes asynchronous code look synchronous. Use `try...catch` to handle errors cleanly.

javascript
async function fetchUsers() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) throw new Error('Failed to fetch users');
    const data = await response.json();
    console.log(data);
  } catch (err) {
    console.error('Error fetching users:', err.message);
  }
}

fetchUsers();

Handling Multiple Async Operations

When running multiple async operations, each can fail independently. `Promise.allSettled` is useful to handle them without failing the entire batch.

javascript
const urls = [
  'https://jsonplaceholder.typicode.com/users',
  'https://jsonplaceholder.typicode.com/posts',
  'https://jsonplaceholder.typicode.com/invalid'
];

async function fetchAll() {
  const results = await Promise.allSettled(urls.map(url => fetch(url)));

  results.forEach((result, i) => {
    if (result.status === 'fulfilled') {
      console.log(`Success from ${urls[i]}`);
    } else {
      console.error(`Failed to fetch ${urls[i]}:`, result.reason);
    }
  });
}

fetchAll();

Retrying Failed Requests

Sometimes a network failure is temporary. You can implement retry logic to attempt the request again.

javascript
async function fetchWithRetry(url, retries = 3, delay = 1000) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url);
      if (!res.ok) throw new Error('Network error');
      return await res.json();
    } catch (err) {
      console.warn(`Attempt ${i + 1} failed. Retrying in ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error('All retries failed');
}

fetchWithRetry('https://jsonplaceholder.typicode.com/users')
  .then(data => console.log('Data fetched:', data))
  .catch(err => console.error(err.message));

Handling API Errors Gracefully

Always check for both network errors and API-specific errors in the response body. This ensures your app handles unexpected API responses without crashing.

javascript
async function safeApiCall(url) {
  try {
    const res = await fetch(url);
    const data = await res.json();

    if (data.error) {
      throw new Error(data.error.message);
    }

    return data;
  } catch (err) {
    console.error('API call failed:', err.message);
    return null;
  }
}

Mini Challenge

1. Fetch a list of users and their posts. Handle both network errors and invalid responses. 2. Implement retry logic for failed fetches. 3. Display errors to the user without breaking the UI. 4. Use `Promise.allSettled` to fetch multiple endpoints and handle each result individually.

MDN Docs: Handling Common Fetch Errors

JavaScript.info: Async/await

MDN Docs: Promise.allSettled