Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi try...catch
- 2.1 Kod
- 2.2 catch parametri — xato obyekti
- 3. Bajarilish tartibi
- 3.1 Qadamma-qadam
- 3.2 Xato chaqiruvlar steki bo'ylab ko'tariladi
- 4. try ichidagi o'zgaruvchi tashqarida ko'rinmaydi
- 5. catch parametrisiz: optional catch binding
- 6. finally: har doim bajariladigan blok
- 6.1 Nima uchun kerak
- 6.2 return bo'lsa ham
- 6.3 Tuzoq: finally ichida return
- 7. Xatoni qayta tashlash
- 7.1 catch hammasini ushlaydi
- 7.2 throw xato — "bu meniki emas"
- 8. try nimani ushlamaydi
- 9. Brauzerda: oshxona ekrani
- 10. Ko'p uchraydigan xatolar
- 10.1 Bo'sh catch — xatoni yutib yuborish
- 10.2 Butun funksiya try ichida
- 10.3 try dagi const ni tashqarida ishlatish
- 10.4 finally da return
- 10.5 try taymer yoki tinglovchi tashqarisida
- 11. Mashqlar
- 1-mashq (oson): Xavfsiz o'qish
- 2-mashq (o'rta): Kunlik hisob
- 3-mashq (qiyin): Faqat o'zimizniki
- 4-mashq: Vazifalar qadami — JSON import
- 12. Real ishda
- Xulosa
- Manbalar
JavaScript try...catch...finally: xatoni ushlash va dasturni yiqitmaslik
Qisqacha: Xato chiqishi mumkin bo'lgan kodni
try { ... }ichiga yozasiz. Xato chiqsa, JavaScripttryning qolgan qatorlarini tashlab,catch (xato) { ... }ga o'tadi — dastur yiqilmaydi. Shundan keyinfinally { ... }har doim bajariladi: xato bo'lsa ham, bo'lmasa ham.catchfaqat o'zi hal qila oladigan xatoni ushlashi kerak, qolganinithrow xatobilan yuqoriga qaytaradi.
Bu darsda
try/catchbilanJSON.parsekabi xavfli chaqiruvni o'rab, dasturni yiqitmasdan ishlata olasiz.- Xato chiqqanda kod qaysi tartibda bajarilishini qadamma-qadam tushuntira olasiz.
catchparametridan xato turini va matnini o'qiysiz, keraksiz bo'lsa uni tashlab yozasiz (catch { }).finallyni qachon ishlatishni va undagireturnnega xavfli ekanini bilasiz.- Begona xatoni
throw xatobilan qayta tashlab, uni "yutib yubormaslikni" o'rganasiz. vazifalarga JSON import qo'shasiz.
Oldin bilishingiz kerak: Stack trace va xato turlari, JSON asoslari, JSON chuqur, Execution context va call stack, Prototype pollution.
1. Nega bu kerak?
JSON asoslari darsida JSON.parse buzilgan matnni ko'rsa, SyntaxError bilan hamma ishni to'xtatishini ko'rdik. O'shanda "xatoni ushlashni keyin o'rganamiz" degan edik. O'sha "keyin" — bugun.
«Bahor»dagi vaziyat. Ofitsiant Otabek buyurtmani planshetga kiritadi, planshet uni JSON matni qilib oshxonaga yuboradi. Bir kuni planshet zaryadi tugab, matnning faqat yarmi yetib keldi. Oshxona dasturi Node'da ishlaydi va matnni JSON.parse bilan o'qiydi:
const kelgan = '{"stol": 4';
const buyurtma = JSON.parse(kelgan);
console.log(buyurtma.stol);
console.log("Keyingi buyurtmani kutyapman...");SyntaxError: Expected ',' or '}' after property value in JSON at position 10 (line 1 column 11)Ikkala console.log ham ishlamadi. Stack trace darsidan bilasiz: Node'da ushlanmagan xato butun dasturni to'xtatadi. Ya'ni bitta buzuq buyurtma tufayli oshxona ekrani o'chdi. Keyingi o'nta to'g'ri buyurtma ham endi kelmaydi.
Bu yerda kodda xato yo'q. Buzilgan narsa — tashqaridan kelgan ma'lumot. Uni oldindan to'liq tekshirib bo'lmaydi: matnning to'g'ri JSON ekanini bilishning yagona ishonchli yo'li — uni o'qib ko'rish. Demak bizga shunday vosita kerak: "o'qib ko'r, xato chiqsa — dasturni yiqitma, menga ayt".
Hayotdan o'xshatish: sirkdagi xavfsizlik to'ri. Akrobat baland arqonda yuradi. U yiqilishi mumkin, shuning uchun pastga to'r tortiladi. Yiqilsa — to'rga tushadi, tomosha davom etadi. try — "arqon ustidagi" xavfli harakat, catch — to'r.
2. Birinchi try...catch
2.1 Kod
Xuddi shu buzuq buyurtma, endi to'r bilan:
const kelgan = '{"stol": 4';
try {
const buyurtma = JSON.parse(kelgan);
console.log("Qabul qilindi:", buyurtma.stol);
} catch (xato) {
console.log("Buyurtma o'qilmadi:", xato.name);
}
console.log("Keyingi buyurtmani kutyapman...");Konsolda:
Buyurtma o'qilmadi: SyntaxError
Keyingi buyurtmani kutyapman...Dastur yiqilmadi. Qismlarini ko'raylik:
try { ... }— "sinab ko'r" bloki. Ichidagi kod odatdagidek bajariladi.catch (xato) { ... }— "ushla" bloki. U faqattryichida xato chiqqanda ishlaydi.xato— ushlangan xato obyekti. Nomini o'zingiz tanlaysiz, xuddi funksiya parametri kabi. Kodlarda ko'pinchaerror,erryokiedeyiladi; bizxatodeymiz.- Blokdan keyingi kod —
console.log("Keyingi...")— xato bo'lsa ham, bo'lmasa ham davom etadi.
Atama: xato "tashlanadi" va "ushlanadi". JSON.parse buzuq matnni ko'rganda xato tashlaydi (throw). Tashlangan xatoni boshqa ko'p tillarda istisno (exception) deyishadi — dasturning odatdagi yo'lidan "istisno" holat. catch uni ushlaydi (catch). O'zingiz xato tashlashni keyingi darsda o'rganasiz. Bugun JavaScript'ning o'zi tashlaydigan xatolarni ushlaymiz.
Endi kelgan ni to'g'ri matnga almashtiring: '{"stol": 4}'. Natija — Qabul qilindi: 4 va Keyingi buyurtmani kutyapman.... catch bloki umuman ishlamadi.
2.2 catch parametri — xato obyekti
Stack trace darsida ko'rgansiz: xato — obyekt, uning name (turi) va message (matni) bor. catch aynan shu obyektni oladi:
try {
JSON.parse("Manti");
} catch (xato) {
console.log(xato.name);
console.log(xato.message);
console.log(xato instanceof SyntaxError);
}Konsolda:
SyntaxError
Unexpected token 'M', "Manti" is not valid JSON
trueKonsolga chiqqan matn — konsolda qizil xato bo'lib chiqadigan matnning aynan o'zi, faqat endi u qiymat. Uni o'qish, solishtirish, ekranga chiqarish mumkin. instanceof — "shu klassdan yaratilganmi?" tekshiruvi (Object.create va instanceof). SyntaxError ham klass, va u Error dan meros oladi (Meros).
Bitta muhim fikr: xato.message — dasturchi uchun yozilgan, inglizcha matn. Uni o'zgarishsiz foydalanuvchiga ko'rsatish yaxshi emas: Otabek "Unexpected token" dan hech narsa tushunmaydi. Foydalanuvchiga o'z tilidagi, nima qilish kerakligini aytadigan xabar ko'rsatiladi. Bu qoidaga Xato strategiyasi darsida qaytamiz.
Tekshirib ko'ring:
tryichida xato bo'lmasa,catchdagi kod bajariladimi?catchdan keyingi kod-chi?
Javob
catch dagi kod bajarilmaydi — u faqat xato chiqqanda ishlaydi. catch dan keyingi kod esa ikkala holatda ham bajariladi: try...catch bloki tugagach, dastur odatdagidek pastga davom etadi.
3. Bajarilish tartibi
3.1 Qadamma-qadam
Xato chiqqan zahoti nima bo'ladi? try ning qolgan qatorlari tashlab ketiladi. Quyidagi kodda raqamlangan xabarlar bor. Keyingi tugmasini bosing va 3-xabar nega chiqmasligiga qarang:
Uchta qoida:
- Xato chiqqan qatordan keyingi
tryqatorlari bajarilmaydi. Xatodan oldingi qatorlar esa bajarilgan bo'ladi — ularni "orqaga qaytarib" bo'lmaydi. - Xato bo'lsa —
catch, bo'lmasa —catcho'tkazib yuboriladi. finally(bu blok haqida «finally» bo'limida) va blokdan keyingi kod — ikkala holatda ham.
Birinchi qoidaga e'tibor bering. Stack trace darsida savat misolida jami ga narx qo'shilib ulgurgan, ekran esa yangilanmagan edi. try ham shunday: u xatodan oldin bajarilgan ishni bekor qilmaydi. Holat yarim o'zgargan bo'lib qolishi mumkin. Shuning uchun xavfli qadamni holatni o'zgartirishdan oldin qo'ying — «Vazifalar qadami» da aynan shunday qilamiz.
Butun yo'l bitta sxemada:
flowchart TD
T["try bloki"] --> Q{"Xato chiqdimi?"}
Q -- "yo'q" --> F["finally"]
Q -- "ha: try ning qolgani tashlanadi" --> C["catch (xato)"]
C --> F
F --> D["blokdan keyingi kod"]3.2 Xato chaqiruvlar steki bo'ylab ko'tariladi
Xato try ning o'zida emas, u chaqirgan funksiyaning ichida chiqsa-chi? Mehmon menyuda yo'q taomni so'radi:
const menyu = {
osh: { narx: 35000 },
manti: { narx: 30000 },
};
function narxniOl(taom) {
return menyu[taom].narx;
}
function chekniHisobla(taomlar) {
return taomlar.reduce((jami, t) => jami + narxniOl(t), 0);
}
try {
console.log(chekniHisobla(["osh", "manti"])); // 65000
console.log(chekniHisobla(["osh", "shashlik"]));
} catch (xato) {
console.log("Chek hisoblanmadi:", xato.message);
}Konsolda:
65000
Chek hisoblanmadi: Cannot read properties of undefined (reading 'narx')Xato narxniOl da chiqdi — u yerda try yo'q. JavaScript shunda xatoni chaqiruvchiga uzatadi: reduce ning callback'iga, so'ng reduce ga, so'ng chekniHisobla ga. Hech biri ushlamadi — keyingi qavat. Eng tepadagi try uni ushladi. Yo'ldagi har funksiya o'sha zahoti to'xtadi: chekniHisobla natija qaytarmadi.
Bu — Execution context va call stack darsidagi stekning teskari yo'li. Xato stekning tepasidan pastga qarab, birinchi catch gacha "ko'tariladi". Hech kim ushlamasa — stek bo'shaydi va xato Uncaught bo'ladi.
flowchart BT
A["narxniOl: xato chiqdi"] -- "ushlamadi" --> B["reduce callback"]
B -- "ushlamadi" --> C["chekniHisobla"]
C -- "ushlamadi" --> D["try bloki — catch ushladi"]Amaliy xulosa: try ni har funksiyaga qo'yish shart emas. Uni xatoga javob bera oladigan joyga — bu yerda chekni ekranga chiqaradigan joyga — qo'yasiz. Qayerga qo'yish strategiyasi — Xato strategiyasi darsida.
Tekshirib ko'ring: Yuqoridagi kodda ikkinchi
chekniHisoblaning"osh"uchun narxi hisoblanganmi? Natija qayerga ketdi?
Javob
Hisoblangan: reduce birinchi qadamda 0 + 35000 ni oldi. Ikkinchi qadamda narxniOl("shashlik") xato tashladi va reduce to'xtadi. Oraliq akkumulyator hech qayerga qaytmadi — u yo'qoldi. console.log ham chaqirilmadi: uning argumenti hisoblanmay qoldi.
4. try ichidagi o'zgaruvchi tashqarida ko'rinmaydi
try { } — oddiy blok. Uning ichida const yoki let bilan e'lon qilingan nom faqat shu blok ichida yashaydi (Leksik scope):
try {
const buyurtma = JSON.parse('{"taom": "Osh"}');
} catch (xato) {
console.log("Buzuq matn");
}
console.log(buyurtma.taom);ReferenceError: buyurtma is not definedMatn to'g'ri edi, parse ishladi — lekin buyurtma blok tugashi bilan yo'qoldi. Ikki yechim bor.
Birinchisi — natijani ishlatadigan kodni ham try ichiga olish. Kichik kodda shunday qilinadi.
Ikkinchisi — o'zgaruvchini blokdan oldin let bilan e'lon qilib, ichida qiymat berish:
let buyurtma;
try {
buyurtma = JSON.parse('{"taom": "Osh"}');
} catch (xato) {
console.log("Buzuq matn");
}
console.log(buyurtma.taom); // OshBu usul try ni kichik saqlaydi: ichida faqat xato kutilgan bitta qator. Nega bu muhim — «Ko'p uchraydigan xatolar» da ko'ramiz. Lekin bir narsani unutmang: xato bo'lsa, buyurtma undefined bo'lib qoladi. catch ichida bu holatni hal qiling — masalan, return bilan funksiyadan chiqing. «Vazifalar qadami» da aynan shu qolipni ishlatamiz.
catch (xato) dagi xato ham faqat catch bloki ichida ko'rinadi.
5. catch parametrisiz: optional catch binding
Ba'zan xato obyekti kerak emas — faqat "xato bo'ldimi?" muhim. Masalan, predikat — true/false qaytaradigan funksiya:
function jsonmi(matn) {
try {
JSON.parse(matn);
return true;
} catch {
return false;
}
}
console.log(jsonmi('{"taom": "Osh"}')); // true
console.log(jsonmi("{taom: 'Osh'}")); // false
console.log(jsonmi("")); // falsecatch dan keyin qavs yo'q — bu optional catch binding ("ixtiyoriy bog'lash"). "Bog'lash" — xato obyektini (xato) kabi nomga bog'lash; endi bu majburiy emas. ES2019 da qo'shilgan; Baseline ma'lumotiga ko'ra 2020-yil yanvardan barcha asosiy brauzerlarda bor, 2022-yil iyuldan esa keng qo'llab-quvvatlanadi. Xato obyektini ishlatmasangiz, uni yozmang: o'qigan odam "bu yerda xato turi ahamiyatsiz" deb darhol tushunadi.
Ehtiyot bo'ling: catch { } — "har qanday xato bo'lsa". jsonmi uchun bu to'g'ri, chunki try da faqat JSON.parse turibdi. try katta bo'lsa, parametrsiz catch boshqa xatolarni ham jimgina yutib yuboradi.
Tekshirib ko'ring:
jsonmi("35000")vajsonmi("null")nima qaytaradi?
Javob
Ikkalasi ham true. 35000 — to'g'ri JSON (son), null ham to'g'ri JSON (JSON asoslari darsidagi "matn ichida faqat bitta qiymat"). jsonmi faqat "o'qiladimi?" deb so'raydi, "bu buyurtmami?" deb emas. Matn kerakli tuzilmada ekanini alohida tekshirish kerak — bu «Vazifalar qadami» va keyingi darslarning mavzusi.
6. finally: har doim bajariladigan blok
6.1 Nima uchun kerak
Ba'zi ishlar natijadan qat'i nazar bajarilishi shart. Planshet buyurtmani o'qiyotganda ekranda "band" belgisi yonadi. O'qish muvaffaqiyatli bo'lsa ham, xato bo'lsa ham, oxirida belgi o'chishi kerak — aks holda planshet abadiy "band" bo'lib qoladi.
function buyurtmaniOqi(matn) {
console.log("Planshet: band");
try {
const buyurtma = JSON.parse(matn);
console.log(`Qabul: ${buyurtma.taom}`);
} catch (xato) {
console.log(`Rad etildi: ${xato.name}`);
} finally {
console.log("Planshet: bo'sh");
}
}
buyurtmaniOqi('{"taom": "Manti"}');
buyurtmaniOqi("Manti");Konsolda:
Planshet: band
Qabul: Manti
Planshet: bo'sh
Planshet: band
Rad etildi: SyntaxError
Planshet: bo'shIkkala chaqiruvda ham "bo'sh" chiqdi. Xuddi shu natijaga finally siz ham erishsa bo'lardi: qatorni try oxiriga va catch oxiriga — ikki joyga — yozib. Lekin ikki nusxa — biri unutiladigan nusxa. finally "tozalash" ishini bitta joyda saqlaydi.
6.2 return bo'lsa ham
finally ning asl kuchi shu: u try dan return bilan chiqib ketilganda ham ishlaydi.
const menyu = { osh: 35000, manti: 30000 };
function narxniTop(taom) {
try {
return menyu[taom] ?? 0;
} finally {
console.log(`Qidiruv tugadi: ${taom}`);
}
}
console.log(narxniTop("osh"));Konsolda:
Qidiruv tugadi: osh
35000Tartibga qarang: finally ning xabari oldin chiqdi. return menyu[taom] ?? 0 qiymatni hisoblab qo'ydi, lekin funksiyadan chiqishdan oldin finally ishladi. Shundan keyingina qiymat chaqiruvchiga yetdi.
Bu misolda catch yo'q — try...finally ham to'g'ri yozuv. U "xatoni ushlamayman, lekin tozalashni albatta qilaman" degani. try da xato chiqsa, finally ishlaydi, keyin xato yuqoriga ko'tarilishda davom etadi.
Uchta yozuv bor: try...catch, try...finally va try...catch...finally. Faqat try ning o'zi bo'lmaydi:
try {
JSON.parse("{");
}
console.log("davom");SyntaxError: Missing catch or finally after tryTarjimasi: "try dan keyin catch yoki finally yo'q". Bu kodning yozuv xatosi: fayl umuman ishga tushmaydi, JSON.parse gacha ham yetib bormaydi.
6.3 Tuzoq: finally ichida return
finally har doim oxirgi so'zni aytadi — va bu xavfli bo'lishi mumkin:
function oqi(matn) {
try {
return JSON.parse(matn);
} catch (xato) {
console.log("catch:", xato.name);
return null;
} finally {
return "finally";
}
}
console.log(oqi('{"taom": "Osh"}'));
console.log(oqi("{"));Konsolda:
finally
catch: SyntaxError
finallyIkkala chaqiruvda ham natija — "finally". To'g'ri o'qilgan obyekt ham, catch qaytargan null ham yo'qoldi. finally dagi return oldingi return ni bosib ketadi.
Undan ham yomoni — finally dagi return xatoni ham "yo'q qiladi":
function yutadi() {
try {
JSON.parse("{");
} finally {
return "hammasi joyida";
}
}
console.log(yutadi()); // hammasi joyidacatch yo'q edi, xato yuqoriga ko'tarilishi kerak edi. Lekin finally dagi return uni o'chirib yubordi — dastur "hammasi joyida" deb yolg'on gapirdi. Xato izsiz yo'qoldi.
Qoida: finally ichida return yozmang (throw, break va continue ham shunday ta'sir qiladi). finally faqat tozalash uchun: belgini o'chirish, hisoblagichni yangilash, resursni yopish. Natija try va catch da qaytariladi. Kod sifatini tekshiruvchi ESLint vositasida buning uchun alohida qoida bor — no-unsafe-finally (ESLint'ni 12-qismda o'rganamiz, hozir bilish shart emas).
Tekshirib ko'ring:
function f() { try { return 1; } finally { console.log(2); } }—console.log(f())nima chiqaradi va qaysi tartibda?
Javob
Avval 2, keyin 1. return 1 qiymatni tayyorlab qo'ydi, funksiyadan chiqishdan oldin finally ishladi va 2 ni chiqardi. Keyin 1 chaqiruvchiga qaytdi. finally da return yo'q — shuning uchun 1 o'zgarmadi.
7. Xatoni qayta tashlash
7.1 catch hammasini ushlaydi
catch xato turini tanlamaydi — try ichida chiqqan har qanday xatoni oladi. Bu yerda muammo yashirinib yotadi. Oshxonada taomlar soni hisoblanadi:
function taomlarSoni(matn) {
try {
const buyurtma = JSON.parse(matn);
return buyurtma.taomlar.length;
} catch {
console.log("JSON buzilgan");
return 0;
}
}
console.log(taomlarSoni('{"taomlar": ["Osh", "Choy"]}'));
console.log(taomlarSoni('{"stol": 4}'));Konsolda:
2
JSON buzilgan
0Ikkinchi matn — to'g'ri JSON. Unda shunchaki taomlar yo'q: buyurtma.taomlar.length — TypeError. catch esa uni ham ushladi va "JSON buzilgan" deb yolg'on gapirdi. Otabek planshetni qayta-qayta tekshiradi — muammo esa boshqa joyda.
7.2 throw xato — "bu meniki emas"
Yechim: catch faqat o'zi tushunadigan xatoni hal qilsin. Qolganini — throw xato; bilan — yuqoriga qaytarsin. throw — "xatoni tashla" ko'rsatmasi; uni to'liq keyingi darsda o'rganamiz. Bugun faqat bitta shakli: ushlangan xatoni o'zgarishsiz qayta tashlash.
function taomlarSoni(matn) {
try {
const buyurtma = JSON.parse(matn);
return buyurtma.taomlar.length;
} catch (xato) {
if (xato instanceof SyntaxError) {
console.log("JSON buzilgan");
return 0;
}
throw xato;
}
}
console.log(taomlarSoni("{"));
console.log(taomlarSoni('{"stol": 4}'));JSON buzilgan
0
TypeError: Cannot read properties of undefined (reading 'length')Endi buzuq JSON hamon yumshoq hal qilinadi, taomlar yo'qligi esa haqiqiy xato bo'lib chiqdi — turi va matni bilan. U yuqorida kimdir ushlamasa, Uncaught bo'ladi va dasturchi uni darhol ko'radi.
Bu — xatolar bilan ishlashning eng muhim odatlaridan biri. Kutilgan xato (buzuq matn) — dasturning odatiy holati, unga javob tayyor. Kutilmagan xato (kodda taomlar yo'qligini hisobga olmaganmiz) — bug. Bug'ni yashirish uni tuzatishni imkonsiz qiladi. Shuning uchun begona xato qayta tashlanadi.
Bitta tuzoq: instanceof SyntaxError ham to'liq aniq emas. try ichidagi boshqa kod ham SyntaxError tashlashi mumkin (masalan, Stack trace darsidagi noto'g'ri selektor). Eng ishonchli yo'l — try ichida faqat bitta xavfli chaqiruvni qoldirish. Xatolarni o'z turlari bilan ajratish — O'z xato klasslaringiz darsida.
Tekshirib ko'ring:
catch (xato) { throw xato; }—catchsiz yozilgan koddan nimasi bilan farq qiladi?
Javob
Deyarli hech nimasi bilan: xato o'zgarishsiz yuqoriga ketadi. Bunday catch ma'nosiz — uni olib tashlang. Qayta tashlash faqat shart bilan foydali: bir xil xatolarni hal qilib, qolganini qaytarish.
8. try nimani ushlamaydi
try faqat o'z bloki ishlayotgan paytda chiqqan xatoni ushlaydi. Ikki muhim istisno bor.
Keyinroq ishlaydigan kod. Stack trace darsida setTimeout bilan rejalashtirilgan funksiyani ko'rgansiz: uni keyinroq brauzer yoki Node chaqiradi. O'sha paytda try allaqachon tugagan bo'ladi:
try {
setTimeout(() => {
JSON.parse("{");
}, 0);
} catch {
console.log("ushlandi");
}
console.log("try tugadi");try tugadi
SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)"ushlandi" chiqmadi. try faqat taymerni qo'ydi va tugadi — xato 0 ms dan keyin, butunlay boshqa chaqiruvda chiqdi. Hodisa tinglovchilari ham shunday: tinglovchini ulaydigan addEventListener atrofidagi try tinglovchi ichidagi xatoni ushlamaydi. try ni funksiyaning ichiga qo'yish kerak. Tarmoq so'rovlari va Promise (natijasi keyinroq keladigan ish — 11-qismda o'rganamiz) dagi xatolar uchun boshqa yo'l bor — uni 11-qismda o'rganamiz.
Faylning yozuv xatosi. Fayl ichida SyntaxError bo'lsa (yopilmagan qavs, Missing catch or finally), kod umuman ishga tushmaydi — try ham. try faqat ishlash paytidagi xatolarni ushlaydi: JSON.parse kabi funksiyalar matnni o'qiyotganda tashlaydiganlarini.
9. Brauzerda: oshxona ekrani
Endi brauzerda. Planshetdan kelgan matn maydonda turibdi. «Qabul qilish» bosilganda u o'qiladi, xato bo'lsa — tushunarli xabar chiqadi. Pastdagi hisoblagich finally da yangilanadi:
<style>
body { margin: 1rem; font: 1rem/1.5 system-ui, sans-serif; }
textarea, button { font: inherit; }
textarea { width: 100%; box-sizing: border-box; }
button { min-height: 2.75rem; }
#xabar { min-height: 1.5em; font-weight: bold; }
</style>
<label for="buyurtma">Planshetdan kelgan matn</label>
<textarea id="buyurtma" rows="3">
{"stol": 4, "taomlar": ["Osh", "Ko'k choy"]}</textarea>
<button type="button" id="qabul">Qabul qilish</button>
<p id="xabar" aria-live="polite"></p>
<p id="hisob"></p>
<script>
const maydon = document.getElementById("buyurtma");
const xabar = document.getElementById("xabar");
const hisob = document.getElementById("hisob");
let tekshiruvlar = 0;
function qabulQil() {
try {
const b = JSON.parse(maydon.value);
xabar.textContent = `${b.stol}-stol: ${b.taomlar.join(", ")}`;
} catch (xato) {
xabar.textContent = "Matn buzilgan. Qayta yuborishni so'rang.";
console.log(`${xato.name}: ${xato.message}`);
} finally {
tekshiruvlar++;
hisob.textContent = `Tekshiruvlar: ${tekshiruvlar}`;
}
}
const tugma = document.getElementById("qabul");
tugma.addEventListener("click", qabulQil);
qabulQil();
</script>Sahifa ochilganda — "4-stol: Osh, Ko'k choy", "Tekshiruvlar: 1". Sinab ko'ring:
- Matn oxiridagi
}ni o'chiring va bosing. Ekranda — o'zbekcha xabar, konsolda esa dasturchi uchun asl matn:SyntaxError: Expected ',' or '}' after property value in JSON at position 43 (line 1 column 44). Hisoblagich oshdi —finallyishladi. - Matnni tiklang, «Qabul qilish» — yana to'g'ri natija. Sahifa bir marta ham "o'lmadi".
- Endi
"taomlar"so'zini"taom"ga o'zgartiring. Ekranda yana "Matn buzilgan", konsolda esaTypeError: Cannot read properties of undefined (reading 'join'). Matn buzilmagan — tuzilma boshqa! «Xatoni qayta tashlash» bo'limidagi muammo aynan shu. Uni keyingi darsdathrowbilan to'g'ri hal qilamiz.
aria-live="polite" — ekran o'quvchisi uchun: xabar matni o'zgarsa, NVDA uni o'qib beradi (Dinamik UI'da qulaylik). Malika xato xabarini ko'rmasdan ham eshitadi.
10. Ko'p uchraydigan xatolar
10.1 Bo'sh catch — xatoni yutib yuborish
try {
chekniHisobla(taomlar);
} catch {}Xato yo'qoldi, hech kim bilmaydi. Natija — noto'g'ri ishlaydigan, lekin "jim" dastur. Debugging metodologiyasi darsidagi eng og'ir xatolar aynan shunday paydo bo'ladi. Tuzatish: catch da kamida xabar bering yoki xatoni qayta tashlang. Faqat aniq sababini bilsangiz (jsonmi kabi) xatoni e'tiborsiz qoldiring.
10.2 Butun funksiya try ichida
try ga 30 qator kod solinsa, catch qaysi qatordagi xatoni ushlaganini bilmaydi — «catch hammasini ushlaydi» bo'limidagi muammo. Tuzatish: try ichida faqat xato kutilgan qator(lar). Natija kerak bo'lsa — let ni blokdan oldin e'lon qiling.
10.3 try dagi const ni tashqarida ishlatish
ReferenceError: buyurtma is not defined — «try ichidagi o'zgaruvchi» bo'limi. Tuzatish: let buyurtma; blokdan oldin.
10.4 finally da return
Natija va xato yo'qoladi. Tuzatish: finally — faqat tozalash.
10.5 try taymer yoki tinglovchi tashqarisida
try { tugma.addEventListener("click", ishla); } catch {} — ishla ichidagi xato ushlanmaydi. Tuzatish: try ni ishla funksiyasining ichiga qo'ying.
11. Mashqlar
1-mashq (oson): Xavfsiz o'qish
xavfsizOqi(matn) funksiyasini yozing: matn to'g'ri JSON bo'lsa — o'qilgan qiymatni, aks holda null qaytarsin. Xato obyekti kerak emas — optional catch binding'dan foydalaning («catch parametrisiz» bo'limi). Uchta matn bilan sinang: '{"taom": "Osh"}', "Osh", "".
Yechim
function xavfsizOqi(matn) {
try {
return JSON.parse(matn);
} catch {
return null;
}
}
console.log(xavfsizOqi('{"taom": "Osh"}')); // { taom: 'Osh' }
console.log(xavfsizOqi("Osh")); // null
console.log(xavfsizOqi("")); // nullBitta kamchiligi bor: xavfsizOqi("null") ham null qaytaradi — matn to'g'ri bo'lsa ham. Chaqiruvchi "buzuq matn" va "matnda null" ni ajrata olmaydi. Ko'p hollarda bu muhim emas. Muhim bo'lsa — natijani obyekt qilib qaytarish usulini Xato strategiyasi darsida ko'ramiz.
2-mashq (o'rta): Kunlik hisob
Kun davomida planshetdan kelgan matnlar massivda. Har birini o'qing: to'g'rilarining summa sini qo'shing, buzuqlarini sanang. Bitta buzuq matn qolganlarini to'xtatmasin. Ishora: try ni sikl ichiga qo'ying; for...of dan foydalaning (for...of).
const kelganlar = [
'{"stol": 1, "summa": 70000}',
'{"stol": 2, "summa": 33000',
'{"stol": 3, "summa": 58000}',
"",
];Yechim
const kelganlar = [
'{"stol": 1, "summa": 70000}',
'{"stol": 2, "summa": 33000',
'{"stol": 3, "summa": 58000}',
"",
];
let tushum = 0;
let buzuqlar = 0;
for (const matn of kelganlar) {
try {
tushum += JSON.parse(matn).summa;
} catch {
buzuqlar++;
}
}
console.log(`Tushum: ${tushum}, buzuq: ${buzuqlar}`);Konsolda:
Tushum: 128000, buzuq: 2try sikl ichida — har matn alohida "to'r" ga ega. Agar try sikl tashqarisida bo'lganida, ikkinchi matn butun siklni to'xtatar va uchinchi buyurtma umuman sanalmas edi.
3-mashq (qiyin): Faqat o'zimizniki
stolniOl(matn) funksiyasini yozing. U buyurtma matnidan stol raqamini qaytarsin. Talablar:
- Buzuq JSON —
"Buyurtma buzilgan"ni konsolga chiqarib,nullqaytarsin. - Boshqa har qanday xato — qayta tashlansin.
finallyda"tekshirildi"chiqsin.
'{"stol": 4}', "{" va "null" bilan sinang. Uchinchisi nima beradi va nega?
Yechim
function stolniOl(matn) {
try {
return JSON.parse(matn).stol;
} catch (xato) {
if (xato instanceof SyntaxError) {
console.log("Buyurtma buzilgan");
return null;
}
throw xato;
} finally {
console.log("tekshirildi");
}
}
console.log(stolniOl('{"stol": 4}'));
console.log(stolniOl("{"));
console.log(stolniOl("null"));tekshirildi
4
Buyurtma buzilgan
tekshirildi
null
tekshirildi
TypeError: Cannot read properties of null (reading 'stol')Uchinchi chaqiruvda "null" — to'g'ri JSON, parse null qaytardi. Keyin null.stol — TypeError. U SyntaxError emas, shuning uchun qayta tashlandi. E'tibor bering: finally baribir ishladi — "tekshirildi" xatodan oldin chiqdi. Qayta tashlangan xato finally dan keyin yuqoriga ketdi.
"null" holatini bug deb hisoblash to'g'rimi? Bu — qaror: tashqaridan kelgan matnda null ham bo'lishi mumkin, demak uni ham "noto'g'ri buyurtma" sifatida yumshoq hal qilish kerak. Bunday tekshiruvni throw bilan qanday yozish — keyingi darsda.
4-mashq: Vazifalar qadami — JSON import
JSON chuqur darsida eksport formatini tayyorladik: { "versiya": 1, "vazifalar": [...] }. Prototype pollution darsida esa kurs/mashqlar/10/35-himoya/xavfsiz-import.js da importning xavfsiz yadrosini yozdingiz: XAVFLI_KALITLAR, oddiyObyektmi, xavfsizBirlashtir, vazifaniOl va paketniOqi. Bugun ularni ilovaga ulaymiz: foydalanuvchi eksport matnini maydonga qo'yadi, tugmani bosadi — ro'yxat almashadi.
Bu — yangi imkoniyat: git switch -c feature/import. Branch'ni xatolar moduli oxirigacha — Xato strategiyasi darsigacha — ochiq qoldiramiz.
Talablar:
index.htmlda eksport maydonidan keyin:Importsarlavhasi, yorliqliid="import-matn"maydon,id="import-tugma"tugma va xato uchun<p id="import-xato" class="xato" aria-live="polite">.vazifalar.jsning "3. Hisoblovchi funksiyalar" bo'limiga35-himoyadagi nomlar (o'zgarishsiz).- Tugma bosilganda:
paketniOqitryichida. Buzuq JSON —#import-xatoda o'zbekcha xabar, maydonga fokus vaaria-invalid="true"; ro'yxat o'zgarmasin. Muvaffaqiyatda — ro'yxat almashsin, filtr «Hammasi» bo'lsin,#elonda "N ta vazifa import qilindi." - Yangi royxat
VazifalarRoyxati.dan(...)bilan yasalsin. Diqqat: render royxatga obuna orqali bog'langan (Dizayn naqshlari).
Yechim
index.html — #eksport-matn dan keyin:
<h2>Import</h2>
<label for="import-matn">Eksport qilingan JSON matni</label>
<textarea id="import-matn" rows="6"></textarea>
<button type="button" id="import-tugma">Import qilish</button>
<p id="import-xato" class="xato" aria-live="polite"></p>.xato stili 09-qismdan bor — xabar qizil chiqadi.
vazifalar.js — "2. Sahifa elementlari" ga:
const importMatn = document.getElementById("import-matn");
const importTugma = document.getElementById("import-tugma");
const importXato = document.getElementById("import-xato");"3. Hisoblovchi funksiyalar" ga — 35-himoya/xavfsiz-import.js dagi XAVFLI_KALITLAR, VAZIFA_MAYDONLARI, oddiyObyektmi, xavfsizBirlashtir, vazifaniOl va paketniOqi (o'zgarishsiz ko'chiring). Ularning ostiga — uch yordamchi:
function importXatosiniKorsat(xabar) {
importXato.textContent = xabar;
importMatn.setAttribute("aria-invalid", "true");
importMatn.focus();
}
function importXatosiniTozala() {
importXato.textContent = "";
importMatn.removeAttribute("aria-invalid");
}
function royxatniAlmashtir(malumotlar) {
holat.vazifalar = VazifalarRoyxati.dan(malumotlar);
holat.vazifalar.obuna(render);
holat.filtr = "hammasi";
holat.tahrirId = null;
render();
}"7. Hodisalar" ga, eksport tinglovchisidan keyin:
importTugma.addEventListener("click", () => {
importXatosiniTozala();
elonQil("");
let malumotlar;
try {
malumotlar = paketniOqi(importMatn.value);
} catch {
importXatosiniKorsat("Matn JSON emas. Eksportni to'liq oling.");
return;
}
royxatniAlmashtir(malumotlar);
elonQil(`${malumotlar.length} ta vazifa import qilindi.`);
});Nimaga e'tibor bering:
tryichida bitta qator. Natijalet malumotlarga yoziladi, u blokdan oldin e'lon qilingan («tryichidagi o'zgaruvchi» bo'limi). Xato bo'lsa —return, vamalumotlardan hech kim foydalanmaydi.- Holat xavfli qadamdan keyin o'zgaradi. Avval o'qish, keyin
royxatniAlmashtir. O'qish yiqilsa, eski ro'yxat joyida qoladi — «Bajarilish tartibi» bo'limidagi qoida. obuna(render)qayta.VazifalarRoyxati.danyangi royxat yasaydi. Eski royxatning tinglovchilari unga ko'chmaydi. Bu qatorni unutsangiz, import ishlaydi, lekin keyingi bosishlar ekranni yangilamaydi — jim xato.idlar esadanichida hisoblanadi: yangi vazifa importdagi eng kattaiddan keyingisini oladi.- Ikki xabar, ikki joy. Xato —
#import-xatoda (maydon yonida,aria-live), muvaffaqiyat — umumiy#elonda.
paketniOqi endi try ichida qanday ishlashini Node'da tekshiring. Yadroni xavfsiz-import.js dan import qilmaymiz (modullar hali o'tilmagan) — qisqartirilgan nusxasi bilan:
function paketniOqi(matn) {
const paket = JSON.parse(matn);
if (paket.versiya !== 1 || !Array.isArray(paket.vazifalar)) {
return [];
}
return paket.vazifalar;
}
const matnlar = [
'{"versiya": 1, "vazifalar": [{"id": 5, "matn": "Choy"}]}',
'{"versiya": 1, "vazifalar": [}',
'{"versiya": 2, "vazifalar": [{"id": 5, "matn": "Choy"}]}',
];
for (const matn of matnlar) {
try {
console.log("O'qildi:", paketniOqi(matn).length);
} catch (xato) {
console.log("Ushlandi:", xato.name);
}
}Konsolda:
O'qildi: 1
Ushlandi: SyntaxError
O'qildi: 0Brauzerda sinab ko'ring (bu ssenariy Chrome 154 da qadamma-qadam tekshirilgan):
- «JSON qilib chiqarish» → matnni nusxalang. "Non olish" ni belgilang. Nusxani import maydoniga qo'yib, «Import qilish» — ro'yxat eksport paytidagi holatiga qaytdi, "3 ta vazifa import qilindi.".
- Import qilingan vazifani belgilang — ekran yangilanadi (obuna ishlayapti). Yangi vazifa qo'shing — u keyingi
idni oladi. {"versiya": 1, "vazifalar": [}— qizil xabar, fokus maydonda, ro'yxat o'zgarmadi. Bo'sh maydon — xuddi shunday.__proto__kalitli paket (35-himoyadagiprotomatni) — vazifalar o'qildi, DevTools konsolida({}).admin—undefined.
Va uchta ochiq muammo — ularni ham sinang, lekin hozir tuzatmang:
{"versiya": 2, ...}— xato yo'q, ro'yxat bo'shab qoldi, "0 ta vazifa import qilindi.".paketniOqinoto'g'ri versiyada jimgina[]qaytaradi — bo'sh eksport bilan farqi yo'q.null— to'g'ri JSON, lekin xabar "Matn JSON emas".xavfsizBirlashtirnullni aylanmoqchi bo'libTypeErrortashladi, parametrsizcatchesa uni JSON xatosi deb o'yladi — «catchhammasini ushlaydi» bo'limidagi tuzoq."bajarildi": "ha"— satr qabul qilindi va vazifa chizilgan ko'rinadi. Turlar tekshirilmayapti.
Birinchi ikkitasini keyingi darsda throw bilan, uchinchisini Xato strategiyasi darsida hal qilamiz.
Commit:
git add index.html assets/js/vazifalar.js
git commit -m "Vazifalar: JSON importni qo'sh (try/catch)"12. Real ishda
- Tashqi ma'lumot chegarasi.
JSON.parse, fayl o'qish, foydalanuvchi kiritgan matn, serverdan kelgan javob — dastur "tashqi dunyo" bilan uchrashadigan har joydatry...catchturadi. Ichki, o'zingiz yozgan kodda esa u kamdan-kam kerak. - Server ilovalari. Express va NestJS (server yozish freymvorklari — kursda keyinroq) har so'rovni o'z
tryichida ishlatadi: bitta so'rovdagi xato serverni yiqitmaydi, foydalanuvchi "500" (serverdagi xato kodi) javobini oladi, qolganlar ishlashda davom etadi. Bu — «Kunlik hisob» mashqidagi "sikl ichidagitry" ning kattalashgan shakli. finally— tozalash. "Yuklanmoqda..." belgisini o'chirish, tugmani qayta faollashtirish, faylni yopish. Resursni avtomatik yopishning yangi usuli —using— shu modulning oxirgi darsida.- Intervyu. "
finallyqachon ishlamaydi?" (javob: deyarli har doim ishlaydi;finallydagireturnnatijani bosib ketadi), "try...catchasinxron xatoni ushlaydimi?", "bo'shcatchnega yomon?" — tez-tez so'raladi.
Xulosa
try— xavfli kod,catch (xato)— xato chiqqanda ishlaydi,finally— har doim. Faqattryning o'zi bo'lmaydi.- Xato chiqqan zahoti
tryning qolgan qatorlari tashlanadi; oldingi qatorlar bekor qilinmaydi. - Xato chaqiruvlar steki bo'ylab birinchi
catchgacha ko'tariladi —tryni javob bera oladigan joyga qo'ying. tryichidagiconst/lettashqarida yo'q;tryni kichik saqlang, natija uchunletni oldinroq e'lon qiling.catch { }— xato obyekti kerak bo'lmaganda;finallydareturnyozmang.catchhamma xatoni ushlaydi: o'zingiznikini hal qiling, begonasinithrow xatobilan qaytaring.
Keyingi dars: throw va Error obyekti — o'zingiz xato tashlashni, message, name, stack va sabablar zanjiri cause ni o'rganamiz va importdagi jim xatolarni yo'qotamiz.
Manbalar
- MDN: "try...catch", "Error" — developer.mozilla.org
- ECMAScript 2025 Language Specification: "The try Statement" — tc39.es/ecma262
- web-features 3.40 (npm paketi):
optional-catch-binding— Baseline 2020-01-15, keng qo'llab-quvvatlanadi 2022-07-15 - ESLint: "no-unsafe-finally" — eslint.org/docs/latest/rules
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!