تماس با ما

مدیریت خطا (Error Handling)

مدیریت خطا (Error Handling)؛ آموزش JavaScript به زبان ساده، همراه با مثال و خروجی.

try / catch / finally

try {
  const data = JSON.parse("{bad json}");
} catch (err) {
  console.log("خطا:", err.message);
} finally {
  console.log("همیشه اجرا می‌شه");   // حتی با return داخل try
}
  • catch بدون پارامتر (ES2019): catch { ... }
  • finally برای آزاد کردن منابع (بستن فایل، قطع اتصال، پنهان کردن loading).

throw

می‌تونی هر مقداری throw کنی ولی همیشه Error بنداز:

function divide(a, b) {
  if (b === 0) throw new Error("تقسیم بر صفر");
  return a / b;
}
try { divide(1, 0); } catch (e) { console.log(e.message); }

ساختار Error

const e = new Error("پیام", { cause: originalError });
e.name;      // → "Error"
e.message;   // → "پیام"
e.stack;     // → رشته‌ی stack trace
e.cause;     // → خطای اصلی (ES2022)

انواع داخلی

نوعوقتی...
Errorعمومی
TypeErrorنوع اشتباه: null.x، 5()
ReferenceErrorمتغیر تعریف نشده
SyntaxErrorساختار نادرست (JSON.parse, eval)
RangeErrorخارج از محدوده (new Array(-1), recursion بی‌نهایت)
URIErrordecodeURI ناصحیح
EvalErrorقدیمی
AggregateErrorچند خطا (Promise.any)
try { null.x; }          catch (e) { e instanceof TypeError;      } // true
try { undefinedVar; }    catch (e) { e instanceof ReferenceError; } // true
try { new Array(-1); }   catch (e) { e instanceof RangeError;     } // true

خطای سفارشی

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

class HttpError extends Error {
  constructor(status, message, options) {
    super(message, options);
    this.name = "HttpError";
    this.status = status;
  }
}

try {
  throw new ValidationError("ایمیل نامعتبر", "email");
} catch (e) {
  if (e instanceof ValidationError) {
    console.log(`${e.field}: ${e.message}`);
  } else {
    throw e;                    // خطایی که نمی‌شناسی رو دوباره بنداز
  }
}

Re-throw و wrap کردن

try {
  JSON.parse(text);
} catch (err) {
  throw new Error("فایل تنظیمات خراب است", { cause: err });
}

خطا در کد ناهمزمان

Callback / setTimeout

try/catch معمولی نمی‌گیره:

try {
  setTimeout(() => { throw new Error("x"); }, 0);   // ❌ گرفته نمی‌شه
} catch {}

Promise

fetch("/x")
  .then((r) => r.json())
  .catch((e) => console.log("خطا:", e))
  .finally(() => console.log("تمام"));

async/await

async function load() {
  try {
    const res = await fetch("/api");
    if (!res.ok) throw new HttpError(res.status, "خطای سرور");
    return await res.json();
  } catch (e) {
    console.error(e);
    return null;
  }
}

fetch فقط روی خطای شبکه reject می‌شه؛ 404/500 رو خودت با res.ok چک کن.

الگوی Go-style

async function to(promise) {
  try { return [null, await promise]; }
  catch (e) { return [e]; }
}
const [err, data] = await to(fetch("/api"));
if (err) { /* ... */ }

خطاهای مدیریت‌نشده (Global)

// مرورگر
window.addEventListener("error", (e) => console.log(e.message));
window.addEventListener("unhandledrejection", (e) => console.log(e.reason));

// Node
process.on("uncaughtException", (e) => { /* لاگ و خروج */ });
process.on("unhandledRejection", (reason) => { /* ... */ });

Promise.allSettled

وقتی نمی‌خوای با اولین خطا همه‌چیز fail بشه:

const results = await Promise.allSettled([p1, p2, p3]);
results.filter((r) => r.status === "rejected");

بهترین روش‌ها

  • فقط جایی catch کن که می‌تونی کاری باهاش بکنی.
  • خطا رو قورت نده: catch {} خالی ممنوع.
  • پیام خطا رو برای کاربر و جزئیات رو برای لاگ جدا نگه دار.
  • از Error استفاده کن (stack trace داره)، نه رشته.
  • با cause زنجیره‌ی خطا رو حفظ کن.
  • ورودی‌ها رو زود validate کن (Guard clause).

دیباگ

console.error(err);
console.trace("از کجا صدا زده شد؟");
console.assert(x > 0, "x باید مثبت باشه");
debugger;      // نقطه‌ی توقف در DevTools

ایده‌ای دارید؟ برایمان بگویید

مشاوره و پیشنهاد اولیه رایگان است.

تماس با ما