WisarWisar
Dasturlash kitobi/2-QISM — JavaScript12 daqiqa

2.12-bob: Error handling — try/catch/finally, throw, custom error

2-QISM — JavaScript (0 dan chuqurgacha) · 12-mavzu


1. Kirish va motivatsiya

Hozirgacha deyarli har bobda try/catch ni sezdik (2.11 ayniqsa). Endi xatolarni boshqarishni to'liq, professional darajada o'rganamiz. Bu — havaskor va professional dasturchi farqini eng aniq ko'rsatadigan mavzu.

Yangi dasturchi "kod ishlasin" deb yozadi. Professional — "kod xato bo'lganda ham to'g'ri ishlasin" deb yozadi. Tarmoq uziladi, foydalanuvchi noto'g'ri ma'lumot kiritadi, fayl topilmaydi, DB javob bermaydi — bularning hammasi sodir bo'ladi. Savol — dasturingiz qulaydimi yoki chiroyli uddasidan chiqadimi.

O'xshatish: xato handling — bu havfsizlik to'ri (akrobat ostidagi). Akrobat yiqilmaslikka harakat qiladi, lekin yiqilsa — to'r uni tutadi. Tor bo'lmagan akrobat — beparvo. Error handling'siz dastur — har tomchi yomg'irda qulaydi.

Xato — dushman emas, balki dasturni mustahkam (robust) qiladigan vosita. Bu bob — 5.10 (Express error middleware), 8.6 (NestJS exception filter) va butun backend ishonchliligining poydevori.


2. Nazariya — chuqur tushuntirish

2.1. Xato turlari

JS'da ikki asosiy xato vaqti:

  • Compile/Syntax xato — kod noto'g'ri yozilgan (qavs yopilmagan). Kod umuman ishlamaydi.
  • Runtime xato — kod ishlaganda yuzaga keladi (undefinedga murojaat, tarmoq uzilishi). Bularni boshqarish kerak.

Asosiy built-in xato turlari (har biri Errordan meros — 2.5):

Xato Qachon
Error umumiy/asosiy
TypeError noto'g'ri tur (undefined.x, funksiyani son kabi)
ReferenceError mavjud bo'lmagan o'zgaruvchi (TDZ — 2.4)
RangeError chegaradan tashqari (stack overflow — 0.1)
SyntaxError noto'g'ri sintaksis (JSON.parse — 2.8)

2.2. try/catch/finally

Xatoni "ushlash"ning asosiy mexanizmi:

js
try {
  // xato yuz berishi mumkin bo'lgan kod
  const data = JSON.parse(matn);   // noto'g'ri JSON  SyntaxError (2.8)
  console.log(data);
} catch (xato) {
  // xato yuz bersa, BU blok ishlaydi (dastur qulamaydi!)
  console.error("Xato:", xato.message);
} finally {
  // HAR HOLDA ishlaydi (xato bo'ldimi, yo'qmi) — tozalash uchun
  console.log("Tugadi");
}
  • try — xavfli kod.
  • catch (xato) — xato ushlanadi; dastur qulamaydi, davom etadi. xatoError obyekti.
  • finallydoim ishlaydi (resurs yopish, tozalash — ulanishni yopish, yuklanish indikatorini o'chirish).

2.3. Error obyekti

Ushlangan xato — Error obyekti; muhim xususiyatlari:

js
try {
  null.x;
} catch (xato) {
  console.log(xato.name);     // "TypeError" — tur (2.1)
  console.log(xato.message);  // "Cannot read properties of null..." — tavsif
  console.log(xato.stack);    // qayerda yuz bergani (debug — 15.5)
}

2.4. throw — o'zi xato "tashlash"

throw — ataylab xato chiqarish; bu joriy ishni to'xtatadi va eng yaqin catchga "sakraydi":

js
function yoshTekshir(yosh) {
  if (typeof yosh !== "number") {
    throw new TypeError("Yosh son bo'lsin");   // ataylab xato (2.1)
  }
  if (yosh < 0 || yosh > 150) {
    throw new RangeError("Yosh 0–150 oralig'ida");   // chegara (2.1)
  }
  return yosh;
}

try {
  yoshTekshir(-5);
} catch (e) {
  console.log(`${e.name}: ${e.message}`);   // "RangeError: Yosh 0–150..."
}

Doim Error obyekti "tashlang" (throw new Error(...)), oddiy string emas (throw "xato"). Error obyektida name, message, stack bor — debug uchun zarur.

2.5. Custom error class — o'z xato turlari

Katta loyihada o'z xato turlaringizni yaratish kerak (Errordan meros — 2.5, 2.10):

js
class ValidatsiyaXatosi extends Error {
  constructor(maydon, xabar) {
    super(xabar);                    // ota Error constructor (2.10: super)
    this.name = "ValidatsiyaXatosi"; // xato nomi
    this.maydon = maydon;            // qo'shimcha ma'lumot
  }
}

class TopilmadiXatosi extends Error {
  constructor(resurs) {
    super(`${resurs} topilmadi`);
    this.name = "TopilmadiXatosi";
    this.status = 404;               // HTTP status 0.4-bob — backendda foydali
  }
}

try {
  throw new TopilmadiXatosi("Foydalanuvchi");
} catch (e) {
  if (e instanceof TopilmadiXatosi) {   // turini tekshir (2.1)
    console.log(e.status, e.message);   // 404 "Foydalanuvchi topilmadi"
  }
}

Nega custom error: turli xatolarni ajratib boshqarish (validatsiya ≠ tarmoq ≠ topilmadi); qo'shimcha ma'lumot (status, maydon); backend'da HTTP statusga bog'lash (5.10, 8.6). instanceof bilan turini tekshirasiz.

2.6. Asinxron xato (2.11 bilan bog'lanish)

async/awaitda xato — oddiy try/catch bilan 2.11-bob:

js
async function userOl(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);   // 0.4 (2.11)
    return await res.json();
  } catch (xato) {
    // tarmoq xatosi YOKI throw qilingan HTTP xato — ikkalasi ham bu yerda
    console.error(xato.message);
    throw xato;   // yoki qayta tashla (yuqori qatlam boshqarsin)
  }
}

Promise'larda (.then) — .catch:

js
userOl(1).then(u => {...}).catch(e => console.error(e));   // (2.11)

UnhandledPromiseRejection 2.11-bob: har asinxron ishning try/catch yoki .catch'i bo'lsin — aks holda xato "yo'qoladi" va dastur (Node'da) qulashi mumkin.

2.7. Xatoni qayerda ushlash — strategiya

Eng muhim qaror: xatoni qayerda ushlash?

  • Past qatlamda (funksiya ichida) — faqat shu yerda hal qila olsangiz ushlang; aks holda qayta tashlang (throw) yoki umuman ushlamang — yuqori qatlam boshqarsin.
  • Yuqori qatlamda (UI, route handler) — foydalanuvchiga chiroyli xabar ko'rsating (5.10: global error handler).
js
//  Xatoni "yutib yuborish" (eng yomon)
try { xavfli(); } catch (e) {}   // jim — xato yo'qoldi, debug imkonsiz!

//  Hech bo'lmasa log yoki qayta tashla
try { xavfli(); } catch (e) { console.error(e); throw e; }

Bo'sh catch — eng katta gunoh. Xatoni ushlab, hech narsa qilmaslik — uni yashiradi; keyin bug'ni topish imkonsiz. Hech bo'lmasa log qiling yoki qayta tashlang.

2.8. Defensive programming — xatoni oldini olish

Xatoni ushlashdan ko'ra, uni oldini olish afzal (0.6: edge case, 0.1: NaN):

js
// Kirishni tekshirish (validatsiya)
function bol(a, b) {
  if (b === 0) throw new Error("Nolga bo'lib bo'lmaydi");   // oldini ol
  return a / b;
}

// Mavjudlikni tekshirish (2.1)
const ism = user?.profil?.ism ?? "Noma'lum";   // optional chaining + nullish

// Tur tekshirish (2.1)
if (!Array.isArray(data)) throw new TypeError("Massiv kutilgan");

3. Sintaksis — tez ma'lumotnoma

js
try {
  // xavfli kod
} catch (xato) {
  // xato.name, xato.message, xato.stack
} finally {
  // doim ishlaydi
}

throw new Error("xabar");           // xato tashlash
throw new TypeError("...");          // maxsus tur

class MyError extends Error {        // custom (2.5)
  constructor(m) { super(m); this.name = "MyError"; }
}
e instanceof MyError                 // turini tekshirish

// async (2.6)
try { await f(); } catch (e) {}
p.then().catch(e => {});

4. Batafsil kod namunalari

Misol 1 — try/catch/finally va Error obyekti

js
function jsonOqi(matn) {
  try {
    const data = JSON.parse(matn);     // noto'g'ri  SyntaxError (2.8)
    return data;
  } catch (xato) {
    console.error(`${xato.name}: ${xato.message}`);   // (2.3)
    return null;                        // xavfsiz standart qiymat
  } finally {
    console.log("Parse urinishi tugadi");   // doim (2.2)
  }
}
jsonOqi('{"ism":"Ali"}');   // {ism:"Ali"}
jsonOqi('buzuq json');      // null + xato log

Misol 2 — throw va validatsiya (2.4, 2.8)

js
function userYarat({ ism, yosh, email }) {
  if (!ism || ism.trim().length < 2) {
    throw new Error("Ism kamida 2 belgi bo'lsin");   // 2.6: string metod
  }
  if (typeof yosh !== "number" || yosh < 0) {
    throw new RangeError("Yosh musbat son bo'lsin");   // (2.1)
  }
  if (!email?.includes("@")) {
    throw new Error("Email noto'g'ri");               // (2.6, 2.1)
  }
  return { ism, yosh, email };
}

try {
  const u = userYarat({ ism: "A", yosh: 19, email: "a@b.uz" });
} catch (e) {
  console.log("Validatsiya xatosi:", e.message);   // "Ism kamida 2 belgi..."
}

Misol 3 — Custom error va instanceof (2.5)

js
class TolovXatosi extends Error {
  constructor(xabar, kod) {
    super(xabar);
    this.name = "TolovXatosi";
    this.kod = kod;          // qo'shimcha (masalan "MABLAG_YETMADI")
  }
}

function tolov(balans, summa) {
  if (summa > balans) {
    throw new TolovXatosi("Mablag' yetarli emas", "MABLAG_YETMADI");
  }
  return balans - summa;
}

try {
  tolov(100, 500);
} catch (e) {
  if (e instanceof TolovXatosi) {           // maxsus xatoni ajratib boshqar (2.5)
    console.log(`To'lov xatosi [${e.kod}]: ${e.message}`);
  } else {
    throw e;                                 // boshqa xatoni qayta tashla (2.7)
  }
}

Misol 4 — Asinxron xato boshqaruvi (2.6, 2.11)

js
class ApiXatosi extends Error {
  constructor(status, xabar) { super(xabar); this.name = "ApiXatosi"; this.status = status; }
}

async function malumotOl(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new ApiXatosi(res.status, `So'rov muvaffaqiyatsiz`);  // 0.4
    return await res.json();
  } catch (xato) {
    if (xato instanceof ApiXatosi && xato.status === 404) {
      console.log("Topilmadi");
      return null;                            // 404 — kutilgan, null qaytar
    }
    console.error("Kutilmagan xato:", xato.message);   // tarmoq va h.k.
    throw xato;                               // qayta tashla (yuqori qatlam — 2.7)
  }
}

5. To'g'ri va noto'g'ri holatlar

1) Bo'sh catch (xatoni yutib yuborish)

js
//  xato yo'qoladi — debug imkonsiz (2.7)
try { ish(); } catch (e) {}

//  hech bo'lmasa log + kerak bo'lsa qayta tashla
try { ish(); } catch (e) { console.error(e); throw e; }

2) String tashlash (Error o'rniga)

js
//  stack/name yo'q (2.4)
throw "Xato yuz berdi";

//  Error obyekti
throw new Error("Xato yuz berdi");

3) Hamma narsani bitta umumiy catch

js
//  barcha xatoni bir xil boshqarish (validatsiya = tarmoq = bug)
try { ... } catch (e) { alert("Xato"); }

//  turini ajrat (2.5)
catch (e) {
  if (e instanceof ValidatsiyaXatosi) korsatMaydonXatosi(e);
  else if (e instanceof ApiXatosi) korsatTarmoqXatosi(e);
  else throw e;   // noma'lumni qayta tashla
}

4) Asinxronda .catch/try-catch unutish

js
//  UnhandledPromiseRejection (2.11)
async function f() { await xavfli(); }
f();   // catch yo'q

// 
f().catch(e => console.error(e));

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — catch xatoni ushlamaydi (asinxronda)

js
try { setTimeout(() => { throw new Error("x"); }, 100); } catch (e) {}  // ushlamaydi!

Sababi: callback keyin ishlaydi — try allaqachon tugagan (2.11: event loop). Yechimi: xatoni callback ichida ushlang, yoki Promise/async-await ishlating 2.6-bob.

Xato 2 — finallyda return catchni "yutadi"

Sababi: finallydagi return try/catchning natijasini/xatosini bekor qiladi. Yechimi: finallyni faqat tozalash uchun ishlating, return/throw qo'ymang.

Xato 3 — Xato messagesiz

js
catch (e) { console.log(e); }   // [object Object] yoki tushunarsiz

Sababi: Error obyekti noto'g'ri chiqarildi. Yechimi: e.message yoki e.stack 2.3-bob.

Xato 4 — Custom error namesiz / supersiz

Sababi: extends Errorda super(message) yoki this.name unutildi 2.5-bob. Yechimi: constructor'da super(m) + this.name = "...".

Xato 5 — Xatoni juda erta yoki juda kech ushlash

Sababi: noto'g'ri qatlamda 2.7-bob. Yechimi: past qatlam — hal qila olsangiz ushlang yoki qayta tashlang; yuqori (UI/route) — foydalanuvchiga ko'rsating.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • Async 2.11-bob: try/catch async bilan; UnhandledPromiseRejection.
  • Express error middleware 5.10-bob: global error handler — barcha xatoni bir joyda.
  • NestJS Exception Filters 8.6-bob: custom error HTTP javob (status — 2.5).
  • Validatsiya 5.9-bob: Zod/Joi xatolari; custom validatsiya error.
  • HTTP status 0.4-bob: custom error'da status — 4xx/5xx ga bog'lash.
  • Logger 5.12-bob: xatoni log qilish (stack bilan — 2.3).
  • Debugging 15.5-bob: stack trace bilan xatoni topish.
  • React Error Boundaries 11.12-bob: komponent xatolari.

8. Eng yaxshi amaliyotlar (best practices)

  • Hech qachon bo'sh catch — log qiling yoki qayta tashlang 2.7-bob.
  • Doim Error obyekti tashlang (throw new Error(...)), string emas 2.4-bob.
  • Custom error class'lar bilan turli xatolarni ajrating (instanceof — 2.5).
  • Xatoni to'g'ri qatlamda ushlang — past: hal qiling yoki qayta tashlang; yuqori: foydalanuvchiga 2.7-bob.
  • finallyni faqat tozalash uchun (return/throw qo'ymang — 6-bo'lim).
  • Asinxronda try/catch/.catchUnhandledPromiseRejectiondan qoching 2.6-bob.
  • Defensive: oldini oling (validatsiya, ?., tur tekshirish — 2.8) — ushlashdan ko'ra afzal.
  • Foydalanuvchiga texnik xato emas, tushunarli xabar ko'rsating; texnik tafsilotni log qiling.

9. Amaliy loyiha: "Mustahkam Forma Validatori va API Klient"

Error handling'ni amalda mustahkamlovchi loyiha.

Maqsad

try/catch/finally, throw, custom error class va asinxron xato boshqaruvini ishlatib, xatoga chidamli (robust) tizim qurish.

Talablar (requirements)

  1. Custom error iyerarxiyasi: AppError (asosiy), undan ValidatsiyaXatosi (maydonli), ApiXatosi (statusli), TopilmadiXatosi (status 404) — extends Error + super + name 2.5-bob.
  2. Forma validatori: ism/email/parol/yoshni tekshirib, noto'g'ri bo'lsa ValidatsiyaXatosi throw qiladi (qaysi maydon — maydonda) (Misol 2).
  3. xavfsizParse(matn): JSON.parseni try/catch bilan o'rab, xato bo'lsa null (Misol 1).
  4. API klient (async): fetch + res.ok tekshiruvi; 404 TopilmadiXatosi, boshqa ApiXatosi; tarmoq xatosi alohida (Misol 4, 2.6).
  5. instanceof bilan boshqarish: chaqiruvchi kod xato turiga qarab har xil munosabat (validatsiya maydonni ko'rsat; 404 "topilmadi"; boshqa umumiy) (2.5, 2.7).
  6. finally: har so'rovdan keyin "yuklanmoqda" indikatorini o'chiring (tozalash — 2.2).
  7. Retry: API xatosida 2 marta qayta urining, keyin taslim bo'ling (2.11 bilan).
  8. To'g'ri qatlam: past funksiyalar throw qiladi; yuqori (asosiy) funksiya try/catch bilan foydalanuvchiga xabar 2.7-bob.

Maslahatlar (hint)

  • Custom error: class AppError extends Error { constructor(m){super(m); this.name=this.constructor.name;} } 2.5-bob.
  • Validator: har tekshiruvda aniq throw new ValidatsiyaXatosi(maydon, xabar).
  • API: if (res.status === 404) throw new TopilmadiXatosi(...) (Misol 4).
  • instanceof zanjiri: aniqdan umumiyga (ValidatsiyaXatosi ApiXatosi else).
  • Retry: tsikl + try { return ... } catch { agar oxirgi urinish bo'lsa throw }.
  • Bo'sh catch ishlatmang — har joyda log yoki qayta tashlang 2.7-bob.

"Tayyor" mezonlari (acceptance criteria)

  • Custom error iyerarxiyasi (extends Error, super, name) ishlaydi.
  • Validator noto'g'ri maydonda aniq ValidatsiyaXatosi tashlaydi.
  • xavfsizParse buzuq JSON'da qulamaydi.
  • API klient 404/tarmoq/boshqa xatoni ajratadi.
  • instanceof bilan xato turiga qarab har xil munosabat.
  • finally tozalashni bajaradi.
  • Retry ishlaydi; oxirida taslim bo'ladi.
  • Hech qayerda bo'sh catch yo'q; string throw yo'q.

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda professional kodning belgisini — error handlingni o'rgandik:

  • Xato turlari: TypeError, ReferenceError, RangeError, SyntaxError (har biri Errordan meros).
  • try/catch/finally: xavfli kod ushlash (qulamaydi) finally (doim, tozalash).
  • throw new Error(...) (string emas!) — ataylab xato; Error obyekti (name/message/stack).
  • Custom error class (extends Error + super + name) — turli xatolarni ajratish (instanceof), qo'shimcha ma'lumot (status).
  • Asinxron 2.11-bob: try/catch/.catch; UnhandledPromiseRejectiondan qoching.
  • Strategiya: bo'sh catch yo'q; to'g'ri qatlamda ushlang; defensive (oldini oling).

Keyingi bob — 2.13-bob: Regular expressions (RegEx). Matn bilan ishlashda 2.6-bob — qidirish, tekshirish, almashtirish — RegEx eng kuchli quroldir. Email, telefon, parol validatsiyasi (2.12-dagi), matndan ma'lumot ajratish — hammasi RegEx bilan ancha qudratli bo'ladi.


Foydalanilgan rasmiy/ishonchli manbalar

  • MDN Web Docs — Control flow and error handling, try...catch, throw
  • MDN Web Docs — Error (va turlari: TypeError, RangeError...)
  • MDN Web Docs — Error.prototype (name/message/stack), custom errors

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
2.12-bob: Error handling — try/catch/finally, throw, custom error — Wisar