11-bo‘lim

Xatoliklarni boshqarish

try/catch/finally, xato turlari, throw, o'z xato sinflaringiz, xatolarni to'g'ri ushlash va tuzatish usullari.

🕑 14 daqiqa o‘qish 📄 545 so‘z 👁 2 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. try / catch / finally
  2. Xato turlari
  3. throw bilan o'z xatolaringiz
  4. O'z xato sinfingiz
  5. Xatoni yutib yuborish - eng yomon odat
  6. finally va return
  7. Amaliy naqsh: qayta urinish
  8. Xato sababini saqlash
  9. Xulosa

Xato bo'lishi muqarrar. Yaxshi dastur xatoni kutadi va uni foydalanuvchiga tushunarli qilib ko'rsatadi.

try / catch / finally #

JavaScript
function boluvchi(a, b) {
    try {
        if (b === 0) {
            throw new Error("Nolga bo'lish mumkin emas");
        }
        return a / b;
    } catch (xato) {
        console.log("Xato ushlandi:", xato.message);
        return null;
    } finally {
        console.log("  (finally har doim ishlaydi)");
    }
}

console.log("Natija:", boluvchi(10, 2));
console.log("Natija:", boluvchi(10, 0));
Natija
  (finally har doim ishlaydi)
Natija: 5
Xato ushlandi: Nolga bo'lish mumkin emas
  (finally har doim ishlaydi)
Natija: null
Uch blokning vazifasi try Xato chiqishi mumkin bo'lgan kod Xato bo'lsa - qolgani bajarilmaydi catch Faqat xato bo'lganda ishlaydi Dastur qulashining oldini oladi finally HAR DOIM ishlaydi xato bo'lsa ham, yo'q ham Tozalash uchun: fayl yopish, yuklanish belgisi finally hatto return dan keyin ham bajariladi
finally - resursni bo'shatishning ishonchli joyi

Xato turlari #

JavaScript
const sinovlar = [
    () => { null.xossa; },
    () => { mavjudEmas(); },
    () => { JSON.parse("{buzuq}"); },
    () => { const x = 1; x = 2; },
    () => { new Array(-1); },
    () => { decodeURIComponent("%"); }
];

for (const sinov of sinovlar) {
    try {
        sinov();
    } catch (xato) {
        console.log(`${xato.name.padEnd(14)} ${xato.message.slice(0, 42)}`);
    }
}
Natija
TypeError      Cannot read properties of null (reading 'x
ReferenceError mavjudEmas is not defined
SyntaxError    Expected property name or '}' in JSON at p
TypeError      Assignment to constant variable.
RangeError     Invalid array length
URIError       URI malformed
TurQachon chiqadi
TypeErrorNoto'g'ri turdagi qiymat bilan amal
ReferenceErrorMavjud bo'lmagan o'zgaruvchi
SyntaxErrorSintaksis xatosi (odatda JSON.parse)
RangeErrorRuxsat etilgan oraliqdan tashqarida
URIErrorNoto'g'ri URI kodlash

throw bilan o'z xatolaringiz #

JavaScript
function yoshTekshirish(yosh) {
    if (typeof yosh !== "number") {
        throw new TypeError("Yosh son bo'lishi kerak");
    }
    if (Number.isNaN(yosh)) {
        throw new RangeError("Yosh NaN bo'la olmaydi");
    }
    if (yosh < 0 || yosh > 150) {
        throw new RangeError("Yosh 0 dan 150 gacha bo'lishi kerak");
    }
    return `Yosh qabul qilindi: ${yosh}`;
}

const kirimlar = [25, "yigirma", -5, 200, NaN];

for (const kirim of kirimlar) {
    try {
        console.log(yoshTekshirish(kirim));
    } catch (xato) {
        console.log(`${xato.name}: ${xato.message}`);
    }
}
Natija
Yosh qabul qilindi: 25
TypeError: Yosh son bo'lishi kerak
RangeError: Yosh 0 dan 150 gacha bo'lishi kerak
RangeError: Yosh 0 dan 150 gacha bo'lishi kerak
RangeError: Yosh NaN bo'la olmaydi
throw "matn" yozmang

JavaScript istalgan qiymatni tashlashga ruxsat beradi:

JavaScript
throw "Xato yuz berdi";        // ishlaydi, lekin yomon
throw 42;                       // bu ham

Muammolari:

  • .message va .name yo'q;
  • Stek izi (stack trace) yo'q - xato qayerdan kelganini bilib bo'lmaydi;
  • instanceof Error false qaytaradi.

Har doim Error yoki uning vorisini tashlang:

JavaScript
throw new Error("Xato yuz berdi");

Ushlaganda ham ehtiyot bo'ling - boshqa kutubxona satr tashlagan bo'lishi mumkin:

JavaScript
catch (xato) {
    const xabar = xato instanceof Error ? xato.message : String(xato);
}

O'z xato sinfingiz #

JavaScript
class ValidatsiyaXatosi extends Error {
    constructor(maydon, xabar) {
        super(xabar);
        this.name = "ValidatsiyaXatosi";
        this.maydon = maydon;
    }
}

class TarmoqXatosi extends Error {
    constructor(kod, xabar) {
        super(xabar);
        this.name = "TarmoqXatosi";
        this.kod = kod;
    }
}

function formaniTekshirish(malumot) {
    if (!malumot.email) {
        throw new ValidatsiyaXatosi("email", "Email kiritilmagan");
    }
    if (!malumot.email.includes("@")) {
        throw new ValidatsiyaXatosi("email", "Email formati noto'g'ri");
    }
    return true;
}

const sinovlar = [{}, { email: "salom" }, { email: "[email protected]" }];

for (const sinov of sinovlar) {
    try {
        formaniTekshirish(sinov);
        console.log("To'g'ri:", sinov.email);
    } catch (xato) {
        if (xato instanceof ValidatsiyaXatosi) {
            console.log(`[${xato.maydon}] ${xato.message}`);
        } else {
            throw xato;
        }
    }
}

const tarmoq = new TarmoqXatosi(404, "Topilmadi");
console.log("Error vorisimi?:", tarmoq instanceof Error);
console.log("Kod           :", tarmoq.code ?? tarmoq.kod);
Natija
[email] Email kiritilmagan
[email] Email formati noto'g'ri
To'g'ri: [email protected]
Error vorisimi?: true
Kod           : 404
Xato turlariga qarab turlicha munosabat

O'z sinflaringiz ushlash mantiqini aniqlashtiradi:

JavaScript
try {
    await sorovYuborish();
} catch (xato) {
    if (xato instanceof ValidatsiyaXatosi) {
        maydonniBelgilash(xato.maydon);        // foydalanuvchiga ko'rsatish
    } else if (xato instanceof TarmoqXatosi) {
        qaytaUrinish();                         // avtomatik takrorlash
    } else {
        throw xato;                             // notanish - yuqoriga uzatish
    }
}

Muhim qoida: tanimagan xatoni qayta tashlang. Aks holda haqiqiy dastur xatosi jimgina yo'qoladi va uni topish juda qiyin bo'ladi.

Xatoni yutib yuborish - eng yomon odat #

JavaScript
// YOMON - xato yo'qoladi
function yomon(matn) {
    try {
        return JSON.parse(matn);
    } catch (xato) {
        return null;               // nima bo'lgani noma'lum
    }
}

// YAXSHI - sabab saqlanadi
function yaxshi(matn) {
    try {
        return { ok: true, malumot: JSON.parse(matn) };
    } catch (xato) {
        return { ok: false, sabab: xato.message };
    }
}

console.log("Yomon  :", yomon("{buzuq}"));

const natija = yaxshi("{buzuq}");
console.log("Yaxshi :", natija.ok, "-", natija.sabab.slice(0, 30));

const togri = yaxshi('{"ism":"Aziza"}');
console.log("To'g'ri:", togri.ok, "-", togri.malumot.ism);
Natija
Yomon  : null
Yaxshi : false - Expected property name or '}' 
To'g'ri: true - Aziza
Bo'sh catch blokini yozmang
JavaScript
try {
    xavfliAmal();
} catch (xato) {
    // hech nima
}

Bu kod xatoni butunlay yashiradi. Dastur noto'g'ri ishlaydi, lekin siz nima uchunligini hech qachon bilmaysiz.

Agar xato haqiqatan ahamiyatsiz bo'lsa, buni izohda yozing:

JavaScript
try {
    localStorage.setItem("kalit", qiymat);
} catch (xato) {
    // Maxfiy rejimda localStorage taqiqlangan - bu normal holat
}

Aks holda kamida jurnalga yozing:

JavaScript
catch (xato) {
    console.error("Saqlab bo'lmadi:", xato);
}

finally va return #

JavaScript
function sinov() {
    try {
        return "try dan";
    } finally {
        console.log("  finally ishladi");
    }
}

console.log(sinov());

// finally ichida return - try ning natijasini BOSIB O'TADI
function xavfli() {
    try {
        return "try dan";
    } finally {
        return "finally dan";      // try ning qiymatini yo'q qiladi
    }
}

console.log(xavfli());
Natija
  finally ishladi
try dan
finally dan
finally ichida return yozmang

Yuqoridagi xavfli() funksiya har doim "finally dan" qaytaradi - try dagi return yo'qoladi.

Undan ham yomoni: finally dagi return tashlangan xatoni ham yutib yuboradi:

JavaScript
function juda_xavfli() {
    try {
        throw new Error("muhim xato");
    } finally {
        return "hammasi joyida";   // xato yo'qoldi!
    }
}

Bu funksiya xato tashlamaydi va muammo butunlay ko'rinmay qoladi.

finally faqat tozalash uchun: fayl yopish, ulanishni uzish, yuklanish belgisini o'chirish.

Amaliy naqsh: qayta urinish #

JavaScript
function beqarorAmal(urinish) {
    if (urinish < 3) {
        throw new Error(`${urinish}-urinish muvaffaqiyatsiz`);
    }
    return "muvaffaqiyat";
}

function qaytaUrinish(amal, maksUrinish = 5) {
    const xatolar = [];

    for (let i = 1; i <= maksUrinish; i++) {
        try {
            const natija = amal(i);
            console.log(`${i}-urinishda o'tdi`);
            return natija;
        } catch (xato) {
            xatolar.push(xato.message);
            console.log(`  ${xato.message}`);
        }
    }

    throw new Error(`${maksUrinish} urinish behuda: ${xatolar.length} xato`);
}

console.log("Natija:", qaytaUrinish(beqarorAmal));

try {
    qaytaUrinish(() => { throw new Error("doimiy xato"); }, 2);
} catch (xato) {
    console.log("Yakuniy:", xato.message);
}
Natija
  1-urinish muvaffaqiyatsiz
  2-urinish muvaffaqiyatsiz
3-urinishda o'tdi
Natija: muvaffaqiyat
  doimiy xato
  doimiy xato
Yakuniy: 2 urinish behuda: 2 xato

Xato sababini saqlash #

JavaScript
function malumotOqish(matn) {
    try {
        return JSON.parse(matn);
    } catch (xato) {
        throw new Error("Sozlama faylini o'qib bo'lmadi", { cause: xato });
    }
}

try {
    malumotOqish("{buzuq}");
} catch (xato) {
    console.log("Xabar :", xato.message);
    console.log("Sabab :", xato.cause.name);
    console.log("Batafsil:", xato.cause.message.slice(0, 30));
}
Natija
Xabar : Sozlama faylini o'qib bo'lmadi
Sabab : SyntaxError
Batafsil: Expected property name or '}' 
cause - xatolar zanjiri

ES2022 dan Error ning ikkinchi argumenti bor:

JavaScript
new Error("yuqori darajadagi xabar", { cause: aslXato });

Bu ikki dunyoni birlashtiradi:

  • Foydalanuvchiga tushunarli xabar;
  • Dasturchiga kerakli texnik tafsilot.

Ilgari buni qo'lda qilishga to'g'ri kelardi:

JavaScript
const yangi = new Error("xabar");
yangi.original = aslXato;          // nostandart

Endi cause standart va console.error uni avtomatik ko'rsatadi.

Server jurnalida to'liq zanjirni ko'rsating, foydalanuvchiga esa faqat yuqori darajadagi xabarni - texnik tafsilot xavfsizlik ma'lumotini oshkor qilishi mumkin.

Amaliy topshiriq
  1. try/catch/finally uchalasi qachon ishlashini ko'rsating.
  2. Beshta xato turini ataylab chiqarib, nomlarini chop eting.
  3. throw new Error va throw "matn" farqini tushuntiring.
  4. ValidatsiyaXatosi sinfini yozing va instanceof bilan ushlang.
  5. Tanimagan xatoni qayta tashlash nima uchun muhimligini ayting.
  6. Bo'sh catch blokining zararini misolda ko'rsating.
  7. finally ichidagi return xatoni yutishini isbotlang.
  8. Qayta urinish funksiyasini yozing.
  9. cause bilan xatolar zanjirini tuzing.
  10. { ok, malumot } naqshi bilan xavfsiz JSON.parse yozing.

Xulosa #

  • try xatoli kodni, catch xatoni, finally tozalashni oladi.
  • finally har doim ishlaydi - return dan keyin ham.
  • Asosiy turlar: TypeError, ReferenceError, SyntaxError, RangeError.
  • throw new Error yozing - satr tashlamang.
  • O'z xato sinflaringiz ushlash mantiqini aniqlashtiradi.
  • Tanimagan xatoni qayta tashlang - yutib yubormang.
  • Bo'sh catch - eng yomon odat; kamida jurnalga yozing.
  • finally ichida return yozmang - xatoni yutadi.
  • cause bilan asl xatoni saqlang.
  • Foydalanuvchiga sodda xabar, jurnalga to'liq zanjir.

Keyingi bo'limda DOM bilan tanishib, sahifani boshqarishni boshlaymiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.