Explain error handling in JavaScript. Compare different error handling strategies and when to use each.

3 minintermediatejavascriptes6errorhandlingstrategies

Quick Answer

Error handling in JavaScript involves catching and managing errors to prevent application crashes.

Detailed Answer

Explain error handling in JavaScript. Compare different error handling strategies and when to use each.

Error handling in JavaScript involves catching and managing errors to prevent application crashes.

Basic Error Handling:

// try-catch blocks
try {
  const result = riskyOperation();
  console.log('Success:', result);
} catch (error) {
  console.error('Error occurred:', error.message);
} finally {
  console.log('This always runs');
}

// Throwing custom errors
function validateAge(age) {
  if (age < 0) {
    throw new Error('Age cannot be negative');
  }
  if (age > 150) {
    throw new Error('Age cannot exceed 150');
  }
  return true;
}

Error Types:

// Built-in error types
throw new Error('Generic error');
throw new TypeError('Type error');
throw new ReferenceError('Reference error');
throw new SyntaxError('Syntax error');
throw new RangeError('Range error');

// Custom error classes
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

class APIError extends Error {
  constructor(message, status, url) {
    super(message);
    this.name = 'APIError';
    this.status = status;
    this.url = url;
  }
}

Error Handling Strategies:

// 1. Defensive programming
function safeDivide(a, b) {
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new TypeError('Arguments must be numbers');
  }
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

// 2. Error boundaries (React pattern)
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    console.error('Error caught:', error, errorInfo);
  }
  
  render() {
    if (this.state.hasError) {
      return <div>Something went wrong.</div>;
    }
    return this.props.children;
  }
}

// 3. Result pattern
class Result {
  constructor(success, data, error) {
    this.success = success;
    this.data = data;
    this.error = error;
  }
  
  static success(data) {
    return new Result(true, data, null);
  }
  
  static failure(error) {
    return new Result(false, null, error);
  }
}

async function safeFetchUser(id) {
  try {
    const user = await fetchUser(id);
    return Result.success(user);
  } catch (error) {
    return Result.failure(error);
  }
}

// 4. Global error handling
window.addEventListener('error', (event) => {
  console.error('Global error:', event.error);
  // Send to error reporting service
});

window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled promise rejection:', event.reason);
  // Send to error reporting service
});

Async Error Handling:

// Promise error handling
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Fetch error:', error));

// Async/await error handling
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch error:', error);
    throw error; // Re-throw if needed
  }
}

// Error handling in loops
async function processItems(items) {
  const results = [];
  const errors = [];
  
  for (const item of items) {
    try {
      const result = await processItem(item);
      results.push(result);
    } catch (error) {
      errors.push({ item, error });
      console.error(`Failed to process item ${item.id}:`, error);
    }
  }
  
  return { results, errors };
}