Error turlari va xatolarni boshqarish — try, catch, finally, custom error

~20 daq · JavaScript · Ilg'or mavzular

Muammodan boshlaylik

Kod har doim kutilganday ishlamaydi. Server javob bermaydi. Foydalanuvchi son o'rniga matn kiritadi. Fayl topilmaydi. Massivda element yo'q.

Agar xato ushlashmasangiz — JavaScript dasturni to'xtatadi. Hamma narsa muzlaydi.

Lekin yaxshi ilova xato bo'lganda ham ishlashda davom etadi. Foydalanuvchiga tushunarli xabar ko'rsatadi. Muhim operatsiyalarni qayta urinib ko'radi. Bu — xatolarni boshqarish (error handling).


JavaScript xato turlari

JavaScript da bir nechta o'rnatilgan xato turi bor. Har biri o'z holati uchun:

TypeError — noto'g'ri tur. null ga xususiyat murojaati, funksiya bo'lmagan narsani chaqirish:

null.ism;          // TypeError: Cannot read properties of null
undefined.length;  // TypeError
"matn"();          // TypeError: "matn" is not a function

ReferenceError — e'lon qilinmagan o'zgaruvchi:

console.log(yoqOzgaruvchi); // ReferenceError: yoqOzgaruvchi is not defined

SyntaxError — kod sintaksisi noto'g'ri:

eval("if (true {"); // SyntaxError: Unexpected token '{'

RangeError — qiymat ruxsat etilgan oraliqdan tashqarida:

new Array(-1);     // RangeError: Invalid array length
(1.5).toFixed(200); // RangeError

URIError — URI funktsiyasida noto'g'ri argument:

decodeURIComponent("%"); // URIError

Har xato ob'ektida ikki asosiy xususiyat bor: message (nima bo'ldi) va stack (qayerda bo'ldi).


try/catch — xatoni ushlab olish

try blokida xato chiqsa — catch ga tushadi. Dastur to'xtamaydi.

try {
  const natija = JSON.parse("bu json emas");
} catch (xato) {
  console.error("JSON noto'g'ri:", xato.message);
}

console.log("Dastur ishlashda davom etmoqda"); // ← chiqadi

Hayotiy o'xshatma

Alpinist. Tog'ga chiqmoqda. try — urinish. Agar yiqilsa (catch) — jarohatsiz omon qolish uchun xavfsizlik tizimi bor. Yiqilish halokatga olib kelmaydi — davom etish mumkin.

catch — o'sha xavfsizlik tizimi. Xato "ushlanadi", dastur halok bo'lmaydi.


catch da xato turini tekshirish

Turli xatolar turlicha hal qilinishi mumkin:

async function yukla(url) {
  try {
    const javob = await fetch(url);

    if (!javob.ok) {
      throw new Error(`Server xatosi: ${javob.status}`);
    }

    return await javob.json();

  } catch (xato) {
    if (xato instanceof TypeError) {
      // Tarmoq uzilishi — fetch o'zi TypeError chiqaradi
      console.error("Internet yo'q yoki server topilmadi");
    } else if (xato instanceof SyntaxError) {
      // JSON parse xatosi
      console.error("Server noto'g'ri JSON yubordi");
    } else {
      // Boshqa xato — bizning throw qilganimiz
      console.error(xato.message);
    }

    return null;
  }
}

finally — har holda

finally — try muvaffaqiyatli tugasa ham, catch ishlasa ham — har holda ishlaydi.

async function ma'lumotOlish() {
  let yuklanmoqda = true;
  spinnerKo'rsat();

  try {
    const javob = await fetch("/api/data");
    return await javob.json();
  } catch (xato) {
    xatoBoshqar(xato);
    return null;
  } finally {
    yuklanmoqda = false;
    spinnerYashir(); // ← xato bo'lsa ham, bo'lmasa ham — spinner o'chadi
  }
}

finally ning eng muhim qoidasi: try da return bo'lsa ham — finally ishlaydi:

function test() {
  try {
    return "try dan qaytish";
  } finally {
    console.log("finally ishladi!"); // ← return bo'lsa ham chiqadi
  }
}

const natija = test();
// "finally ishladi!"
console.log(natija); // "try dan qaytish"

throw — o'z xatomizni chiqarish

Biz ham istaganmizda xato "otib" yuborish (throw) mumkin. Har qanday qiymat — lekin odatda Error ob'ekti:

function bo'lish(a, b) {
  if (b === 0) {
    throw new Error("Nolga bo'lish mumkin emas");
  }
  return a / b;
}

try {
  bo'lish(10, 0);
} catch (xato) {
  console.error(xato.message); // "Nolga bo'lish mumkin emas"
}

Custom Error — o'z xato sinflari

Turli xato turlarini ajratish uchun — o'z xato sinflarini yaratish mumkin. Bu xatoni instanceof bilan farqlashga imkon beradi.

Hayotiy o'xshatma

Kasalxona. Har kasallikning o'z diagnostika varaqasi bor. "Bemor kasalligi bor" emas — "Yurak kasalligi #42" deyiladi. Har xil kasallik — har xil davolash. Custom Error — o'sha aniq diagnostika.

// Asosiy xato sinfi
class IlovaXatosi extends Error {
  constructor(xabar, kod) {
    super(xabar);
    this.name = "IlovaXatosi";
    this.kod  = kod;
  }
}

// Maxsus xato turlari
class TarmoqXatosi extends IlovaXatosi {
  constructor(xabar) {
    super(xabar, "TARMOQ_XATOSI");
    this.name = "TarmoqXatosi";
  }
}

class AuthXatosi extends IlovaXatosi {
  constructor() {
    super("Tizimga kirish talab qilinadi", "AUTH_XATOSI");
    this.name = "AuthXatosi";
  }
}

class ValidationXatosi extends IlovaXatosi {
  constructor(maydon, xabar) {
    super(xabar, "VALIDATSIYA_XATOSI");
    this.name   = "ValidationXatosi";
    this.maydon = maydon;
  }
}

Ishlatish:

async function foydalanuvchiYarat(ma'lumot) {
  if (!ma'lumot.email) {
    throw new ValidationXatosi("email", "Email kiritilmagan");
  }
  if (!ma'lumot.email.includes("@")) {
    throw new ValidationXatosi("email", "Email noto'g'ri formatda");
  }

  try {
    const javob = await fetch("/api/users", {
      method: "POST",
      body: JSON.stringify(ma'lumot),
    });

    if (javob.status === 401) throw new AuthXatosi();
    if (!javob.ok) throw new TarmoqXatosi(`Server xatosi: ${javob.status}`);

    return await javob.json();

  } catch (xato) {
    if (xato instanceof AuthXatosi) {
      loginSahifagaYuborish();
    } else if (xato instanceof ValidationXatosi) {
      formadaXatoKo'rsat(xato.maydon, xato.message);
    } else if (xato instanceof TarmoqXatosi) {
      xabarBerish("Tarmoqda muammo bor, qayta urinib ko'ring");
    } else {
      throw xato; // ← kutilmagan xato — yuqoriga uzatish
    }
  }
}

instanceof bilan har xato turi aniq ajratildi. Har birining o'z davolash usuli.


Xatoni yuqoriga uzatish — re-throw

Agar catch da xatoni to'liq hal qila olmasangiz — uni yuqoriga "uzatish" kerak. Yutib yubormaslik:

async function yukla() {
  try {
    return await fetch("/api");
  } catch (xato) {
    if (xato instanceof TypeError) {
      // Tarmoq xatosi — biz hal qilamiz
      return keshdan();
    }
    // Boshqa xatolar — biz bilmaymiz, yuqoriga
    throw xato;
  }
}

throw xato — xatoni "yutib" yubormaslik. Siz hal qilolmagan xato yuqoridagi catch ga yetadi.


Tez-tez uchraydigan xatolar

Barcha xatoni bir xil ko'rsatish:

// ❌ — har qanday xato uchun bir xil xabar
catch (xato) {
  alert("Xato yuz berdi"); // foydalanuvchi nima qilishini bilmaydi
}

// ✅ — xato turiga qarab munosib javob
catch (xato) {
  if (xato instanceof ValidationXatosi) {
    formadaKo'rsat(xato.message); // foydalanuvchi tuzatishi mumkin
  } else if (xato instanceof TarmoqXatosi) {
    "Qayta urinib ko'ring"; // vaqtinchalik muammo
  } else {
    "Kutilmagan xato, murojaat qiling"; // bizning xatoimiz
  }
}

Asinxron xatoni try/catch siz qoldirish:

// ❌ — async funksiyadan xato ushlashsiz
async function yukla() {
  const data = await fetch("/api"); // xato bo'lsa — unhandled rejection
}

// ✅
async function yukla() {
  try {
    const data = await fetch("/api");
  } catch (xato) {
    // ...
  }
}

Xulosa

JavaScript da o'rnatilgan xato turlari: TypeError, ReferenceError, SyntaxError, RangeError.

try/catch — xatoni ushlab olish, dastur to'xtamaydi. finally — har holda, resurslarni tozalash uchun.

throw — o'z xatomizni chiqarish. Custom Error — Error dan meros olib, xato turlarini ajratish.

instanceof — catch da xato turini aniqlash. Kutilmagan xatoni throw xato bilan yuqoriga uzatish.


Keyingi dars

64-dars: Regular Expression — asoslar va amaliyot