Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

Custom Errors ใน JavaScript: สร้างคลาสข้อผิดพลาดเฉพาะทาง


Custom Errors (ข้อผิดพลาดแบบกำหนดเอง) ช่วยให้จัดการข้อผิดพลาดได้ละเอียดและมีความหมายมากกว่า Error ธรรมดา โดยการสร้างคลาสที่ extends Error พร้อมเพิ่มฟิลด์ เช่น code, statusCode, details เพื่อใช้ใน error handling, logging, และ API response

ตัวอย่างโค้ด

<!DOCTYPE html>
<html lang="th">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Custom Errors</title>
  <style>
    body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
    .result { font-size: 18px; font-weight: 500; color: rebeccapurple; }
  </style>
</head>
<body>
  <h1>Custom Errors ใน JavaScript</h1>
  <div class="result"></div>
  <button class="Btn">คลิกที่นี่</button>
  <h3>กดปุ่มเพื่อสร้างและแสดง Custom Error</h3>
  <script>
    const resEle = document.querySelector(".result");
    const btnEle = document.querySelector(".Btn");
    class CustomError extends Error {
      constructor(message) {
        super(message);
        this.name = "CustomError";
      }
    }
    function test() {
      throw new CustomError("ข้อผิดพลาดใหม่ถูกโยน");
    }
    btnEle.addEventListener("click", () => {
      try {
        test();
      } catch (err) {
        resEle.innerHTML += "err.name = " + err.name + "<br>";
        resEle.innerHTML += "err.message = " + err.message + "<br>";
      }
    });
  </script>
</body>
</html>

ผลลัพธ์

Custom Errors ใน JavaScript: สร้างคลาสข้อผิดพลาดเฉพาะทาง

เมื่อกดปุ่ม "คลิกที่นี่":

Custom Errors ใน JavaScript: สร้างคลาสข้อผิดพลาดเฉพาะทาง

โครงสร้าง Custom Error แบบครบครัน (Best Practice)

// Base class สำหรับแอปพลิเคชัน
class AppError extends Error {
  constructor(message, options = {}) {
    super(message, options); // ES2022: options.cause
    this.name = this.constructor.name;
    this.code = options.code || "APP_ERROR";
    this.statusCode = options.statusCode || 500;
    this.isOperational = options.isOperational ?? true; // คาดการณ์ได้หรือไม่
    this.details = options.details ?? null;
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor);
    }
  }
}

// Specific errors
class ValidationError extends AppError {
  constructor(message, details) {
    super(message, { code: "VALIDATION_ERROR", statusCode: 400, details });
  }
}

class AuthenticationError extends AppError {
  constructor(message = "Unauthorized") {
    super(message, { code: "AUTH_ERROR", statusCode: 401 });
  }
}

class NotFoundError extends AppError {
  constructor(resource) {
    super(`${resource} not found`, { code: "NOT_FOUND", statusCode: 404 });
  }
}

class DatabaseError extends AppError {
  constructor(message, originalError) {
    super(message, { 
      code: "DB_ERROR", 
      statusCode: 500, 
      isOperational: false, // bug จริง ไม่ใช่ business logic
      cause: originalError 
    });
  }
}

การใช้งานใน Express.js / API

app.use((err, req, res, next) => {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({
      error: {
        code: err.code,
        message: err.message,
        details: err.details
      }
    });
  }
  // Programming error / unknown
  console.error("UNHANDLED ERROR:", err);
  res.status(500).json({ error: { code: "INTERNAL_ERROR", message: "Internal server error" } });
});

Error Cause (ES2022) — Error Chaining

try {
  await db.query(sql);
} catch (dbErr) {
  // ห่อหุ้ม error ต้นทางไว้ใน cause
  throw new DatabaseError("Query failed", dbErr);
}

// ตอน catch ด้านนอก
try {
  await service.doSomething();
} catch (err) {
  console.log(err.cause); // เข้าถึง error ต้นทางได้
}

ข้อดีของ Custom Errors

  • แยก Operational Errors (คาดการณ์ได้: validation, not found) กับ Programmer Errors (bug: null reference, syntax)
  • ส่งข้อมูลโครงสร้างไปยัง frontend / monitoring ได้
  • Filter / Handle ได้เฉพาะเจาะจงด้วย instanceof
  • Stack trace ชัดเจน ชี้จุดที่โยนจริง