آموزش مقدماتی NodeJS | مدیریت خطاها

انواع خطاها

در Node.js خطاها را می‌توان به چند دسته‌ی اصلی تقسیم کرد. شناخت این دسته‌ها به شما کمک می‌کند تا در زمان بروز مشکل، سریع‌تر علت را تشخیص دهید و رفتار مناسبی برای برنامه‌تان تعیین کنید.

۱. خطاهای همگام (Synchronous Errors)

این خطاها زمانی رخ می‌دهند که کد شما به‌صورت خط‌به‌خط و پشت‌سرهم اجرا می‌شود و در همان لحظه‌ی اجرای یک دستور، مشکل پیش می‌آید. مثلاً وقتی تابعی را با آرگومان نامعتبر صدا می‌زنید یا به متغیری دسترسی پیدا می‌کنید که تعریف نشده است.

function divide(a, b) {
  if (b === 0) {
    throw new Error("تقسیم بر صفر مجاز نیست");
  }
  return a / b;
}

divide(10, 0); // اینجا خطا پرتاب می‌شود

اگر این خطا در جایی مدیریت نشود، برنامه بلافاصله متوقف می‌شود. برای مدیریت آن معمولاً از بلوک try...catch استفاده می‌کنیم:

try {
  divide(10, 0);
} catch (err) {
  console.log("خطا رخ داد:", err.message);
}

۲. خطاهای غیرهمگام (Asynchronous Errors)

در Node.js بسیاری از عملیات مانند خواندن فایل، درخواست شبکه یا کوئری پایگاه داده به‌صورت غیرهمگام انجام می‌شوند. خطاهای این نوع عملیات در لحظه‌ی اجرای خط کد رخ نمی‌دهند، بلکه بعداً و در قالب callback یا Promise برگردانده می‌شوند. بنابراین نمی‌توان آن‌ها را با try...catch معمولی گرفت.

الف) خطاهای Callback-based

در الگوی callback، معمولاً اولین آرگومان callback به خطا اختصاص داده می‌شود و اگر خطایی نباشد، مقدار آن null است:

const fs = require("fs");

fs.readFile("file.txt", "utf8", (err, data) => {
  if (err) {
    console.log("خطا در خواندن فایل:", err.message);
    return;
  }
  console.log(data);
});

اینجا اگر فایل وجود نداشته باشد، err مقدار می‌گیرد و ما با بررسی آن، خطا را مدیریت می‌کنیم.

ب) خطاهای Promise-based

وقتی از Promise استفاده می‌کنید، خطا از طریق متد .catch() یا با try...catch در کنار async/await مدیریت می‌شود:

const fs = require("fs").promises;

async function readFileAsync() {
  try {
    const data = await fs.readFile("file.txt", "utf8");
    console.log(data);
  } catch (err) {
    console.log("خطا در خواندن فایل:", err.message);
  }
}

۳. خطاهای زمان اجرا (Runtime Errors)

این خطاها در زمان اجرای برنامه رخ می‌دهند و اغلب ناشی از دسترسی به چیزی هستند که وجود ندارد، مانند:

  • TypeError: وقتی روی مقداری عملیاتی انجام می‌دهید که نوع آن مناسب نیست (مثلاً فراخوانی چیزی که تابع نیست).
  • ReferenceError: وقتی به متغیری اشاره می‌کنید که تعریف نشده است.
  • RangeError: وقتی مقداری خارج از محدوده‌ی مجاز است (مثلاً آرایه‌ای با طول منفی).
  • SyntaxError: وقتی کد شما از نظر نگارشی درست نیست و موتور JavaScript نمی‌تواند آن را تفسیر کند.
let obj = null;
console.log(obj.name); // TypeError: Cannot read properties of null
console.log(notDefinedVar); // ReferenceError

۴. خطاهای سیستمی (System Errors)

این خطاها از سمت سیستم‌عامل یا منابع سیستمی می‌آیند و معمولاً دارای یک کد مثل ENOENT، EACCES یا ECONNREFUSED هستند. مثلاً ENOENT یعنی فایل یا مسیر پیدا نشد و EACCES یعنی دسترسی کافی وجود ندارد.

fs.readFile("no-such-file.txt", (err, data) => {
  if (err) {
    console.log(err.code); // ENOENT
    console.log(err.message);
  }
});

۵. خطاهای پرتاب‌شده توسط کاربر (Custom Errors)

شما می‌توانید خودتان خطا تعریف و پرتاب کنید تا شرایط خاص برنامه‌تان را مشخص کنید. این کار با throw و ساخت یک Error یا کلاس مشتق‌شده از آن انجام می‌شود.

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

function checkAge(age) {
  if (age < 0) {
    throw new ValidationError("سن نمی‌تواند منفی باشد");
  }
  return true;
}

استفاده از کلاس‌های خطای سفارشی به شما اجازه می‌دهد در بلوک catch با استفاده از instanceof نوع خطا را تشخیص دهید و رفتار مناسب را اجرا کنید.

۶. خطاهای مدیریت‌نشده (Uncaught Errors)

اگر خطایی در هیچ‌کجا مدیریت نشود، به‌عنوان یک خطای مدیریت‌نشده باقی می‌ماند و در نهایت باعث توقف برنامه می‌شود. برای آگاهی از این خطاها می‌توانید از رویدادهای process استفاده کنید.

process.on("uncaughtException", (err) => {
  console.log("خطای مدیریت‌نشده:", err.message);
});

process.on("unhandledRejection", (reason) => {
  console.log("Promise رد شده بدون مدیریت:", reason);
});

uncaughtException برای خطاهای همگام و unhandledRejection برای Promiseهایی که .catch() ندارند به کار می‌رود. توجه داشته باشید که استفاده از uncaughtException به‌عنوان راه‌حل دائمی توصیه نمی‌شود، چون برنامه پس از آن در وضعیت نامطمئنی قرار می‌گیرد. این رویداد بیشتر برای ثبت لاگ و بستن نرم‌افزار به‌صورت امن مناسب است.

پرسش و پاسخ این درس

برای ثبت پرسش ابتدا در سایت وارد شوید.

  • 1
  • 2