🏠 Home / Hub

🟨 JS Lesson 14 — Error Handling

← Back to JS Menu  |  🏠 Hub

1. Error Types

Error TypeWhen It HappensExample
SyntaxErrorCode parsing — run ပင် မလုပ်ရlet x = ; (missing value)
ReferenceErrorUndefined variable useconsole.log(undeclared)
TypeErrorWrong type operationnull.toString()
RangeErrorNumber out of rangenew Array(-1)
URIErrorBad URI encodingdecodeURIComponent('%')
Custom ErrorApp-specific errorsthrow new ValidationError()
// Error object properties
try {
  null.toString();
} catch (e) {
  e.name;     // "TypeError"
  e.message;  // "Cannot read properties of null"
  e.stack;    // full stack trace (multi-line string)
}

2. try / catch / finally

// Basic try/catch
function divide(a, b) {
  try {
    if (b === 0) throw new Error("Cannot divide by zero");
    return a / b;
  } catch (err) {
    console.error("Error:", err.message);
    return null;
  } finally {
    console.log("divide() called");  // ALWAYS runs
  }
}

divide(10, 2);   // 5, logs "divide() called"
divide(10, 0);   // null, logs error + "divide() called"

// Catch specific error types
function parseJSON(str) {
  try {
    return JSON.parse(str);
  } catch (e) {
    if (e instanceof SyntaxError) {
      return { error: "Invalid JSON format" };
    }
    throw e;  // re-throw unexpected errors
  }
}

parseJSON('{"name":"Ko"}');  // { name: "Ko" }
parseJSON('not json');       // { error: "Invalid JSON format" }

3. Custom Error Classes

// Custom errors — descriptive, catchable
class AppError extends Error {
  constructor(message, statusCode = 500) {
    super(message);
    this.name       = "AppError";
    this.statusCode = statusCode;
  }
}

class ValidationError extends AppError {
  constructor(message, field) {
    super(message, 400);
    this.name  = "ValidationError";
    this.field = field;
  }
}

class NotFoundError extends AppError {
  constructor(resource) {
    super(`${resource} not found`, 404);
    this.name = "NotFoundError";
  }
}

class AuthError extends AppError {
  constructor(message = "Unauthorized") {
    super(message, 401);
    this.name = "AuthError";
  }
}

// Using custom errors
function getUser(id) {
  if (typeof id !== "number") throw new ValidationError("id must be a number", "id");
  if (id <= 0)                throw new ValidationError("id must be positive", "id");
  if (id > 1000)              throw new NotFoundError("User");
  return { id, name: "Ko Ko" };
}

try {
  getUser("abc");
} catch (e) {
  if (e instanceof ValidationError) {
    console.log(`Validation failed on field '${e.field}': ${e.message}`);
  } else if (e instanceof NotFoundError) {
    console.log(`404: ${e.message}`);
  } else if (e instanceof AppError) {
    console.log(`App error ${e.statusCode}: ${e.message}`);
  } else {
    throw e;  // unexpected — let it bubble up
  }
}

4. Async Error Handling

// async/await error handling
async function fetchUser(id) {
  try {
    const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);

    if (!res.ok) {
      throw new AppError(`HTTP ${res.status}`, res.status);
    }

    const data = await res.json();
    return data;

  } catch (e) {
    if (e instanceof TypeError) {
      // Network error (no internet, CORS, etc.)
      throw new AppError("Network error — check connection");
    }
    throw e;  // re-throw AppError or others
  }
}

// Safe wrapper pattern
async function safeCall(fn, ...args) {
  try {
    const data = await fn(...args);
    return { data, error: null };
  } catch (error) {
    return { data: null, error: error.message };
  }
}

// Usage
const { data, error } = await safeCall(fetchUser, 1);
if (error) {
  console.log("Failed:", error);
} else {
  console.log("User:", data.name);
}

5. Global Error Handlers

// Catch unhandled errors globally (browser)
window.addEventListener("error", (event) => {
  console.error("Unhandled error:", event.error);
  // Send to logging service (Sentry, etc.)
});

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

// Node.js global handlers
process.on("uncaughtException", (err) => {
  console.error("Uncaught Exception:", err);
  process.exit(1);  // clean exit
});

process.on("unhandledRejection", (reason, promise) => {
  console.error("Unhandled Rejection:", reason);
  process.exit(1);
});

// Error Boundary pattern (functional)
function withErrorBoundary(fn, fallback) {
  return function(...args) {
    try {
      return fn(...args);
    } catch (e) {
      console.error(e);
      return fallback;
    }
  };
}

const safeParseInt = withErrorBoundary(
  (s) => { if (isNaN(s)) throw new Error("Not a number"); return parseInt(s); },
  0   // fallback
);

safeParseInt("42");   // 42
safeParseInt("abc");  // 0 (fallback)

🎉 JavaScript Complete!

Variables → Conditions → Loops → Functions → Arrays → Objects → DOM → Events → OOP Classes → Inheritance → Prototype → Closures → Design Patterns → Error Handling

🏠 Hub 🟨 JS Menu

← JS 13  |  🏠 Back to Hub

📌 Study Checklist