Maxsus xatoliklar, Error'ni kengaytirish
Ilovamiz murakkablashgani sari, bizga o'z maxsus xato turlari kerak bo'ladi. Masalan, tarmoq operatsiyasida HttpError, ma'lumotlarni tekshirishda ValidationError va hokazo. Bunday xatolar HTTP status kodi yoki noto'g'ri maydon nomi kabi qo'shimcha ma'lumotlarni saqlashi kerak. JavaScriptda o'z xatolarimizni yaratish uchun ularni Errordan meros olib (extends) yasaymiz.
Nega Error'ni kengaytiramiz?
Faraz qilaylik, bizda readUser(json) funksiyasi bor โ u JSON matnini o'qiydi. To'liq ishlashi uchun foydalanuvchida name va age maydonlari bo'lishi kerak. Agar ular bo'lmasa, bu SyntaxError emas โ chunki JSON o'zi to'g'ri. Bu boshqa turdagi xato. Uni ValidationError deb ataymiz.
Bizning xato klassimiz standart xatolar kabi message, name, stack xususiyatlarini qo'llab-quvvatlashi kerak. Buning uchun eng oson yo'l โ o'rnatilgan Error klassidan meros olish.
Error'dan extends qilish
Error klassini kengaytiramiz. Errorning tuzilishi taxminan shunday (soddalashtirilgan):
// JavaScript'ning ichki o'rnatilgan Error klassi (taxminan)
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // o'rnatilgan xatolar uchun turli nomlar
this.stack = /* chaqiruvlar steki */;
}
}
Endi undan ValidationErrorni meros olamiz:
Muhim jihatlar:
super(message)ni chaqirish shart โ buErrorkonstruktorigamessageni beradi vathis.messageni to'g'ri o'rnatadi;this.nameni o'zimiz belgilaymiz โ chunkiErrorkonstruktori uni"Error"qilib qo'yadi. Odatda klass nomi bilan bir xil qilinadi.
instanceof bilan tekshirish
Endi readUserni yozamiz va ValidationError tashlaymiz. Xatoni ushlaganda uning aynan qaysi tur ekanligini instanceof orqali aniqlaymiz:
instanceof nafaqat aynan klassni, balki uning barcha ota-klasslarini ham tan oladi. Ya'ni ValidationError ham Errorning avlodi bo'lgani uchun:
ValidationError) turdan umumiy (Error) tur tomon boradigan tartibda instanceof ishlatiladi. Aks holda umumiy tur birinchi bo'lib "ushlab olib", aniq shohobchalarga yetib bormaydi.Xatoliklar ierarxiyasi
Ilova o'sgani sari, xatolar ham ko'payadi. Masalan, PropertyRequiredError โ aynan qaysi maydon yetishmayotganini bildiradigan aniqroq xato. U ValidationErrordan meros olishi mumkin. Shunday qilib ierarxiya (daraxt) hosil bo'ladi:
Error
โโโ ValidationError
โโโ PropertyRequiredError
E'tibor bering: catchda biz instanceof ValidationError deb tekshirsak, u PropertyRequiredErrorni ham qamrab oladi โ chunki u ValidationErrorning avlodi. Bu ierarxiyaning kuchi: bitta tekshiruv butun bir tarmoqni ushlaydi.
this.nameni har bir konstruktorda qo'lda yozib chiqish zerikarli. Buning o'rniga asosiy maxsus xato klassi yaratib, unda this.name = this.constructor.name deb yozish mumkin โ shunda avlodlar nomni avtomatik oladi.Xatolarni o'rash (Wrapping exceptions)
Ierarxiya foydali, lekin muammosi bor. Faraz qilaylik, readUserni chaqiruvchi kod turli-tuman xatolar (ValidationError, SyntaxError, kelajakda yana boshqalar) haqida qayg'urishi kerak. Har safar yangi xato turi qo'shilganda, uni chaqiruvchi hamma joyda tekshiruvni yangilashimiz kerak bo'ladi. Bu noqulay.
Yechim โ wrapping (o'rash) texnikasi:
- Barcha "quyi darajali" xatolarni umumlashtiruvchi bitta klass yaratamiz โ masalan,
ReadError; readUserichidagitry...catchquyi darajali xatolarni (ValidationError,SyntaxError) ushlaydi;- So'ng ularni bitta umumiy
ReadErrorichiga "o'rab", uni tashlaydi. Asl xato esacause(sabab) xususiyatida saqlanadi.
Endi chaqiruvchi kod faqat bitta ReadErrorni tekshirsa kifoya. Tafsilot kerak bo'lsa, err.causeni ochib ko'radi:
Endi ikkinchi holatni โ validatsiya xatosini โ sinab ko'ring: JSON to'g'ri, lekin maydon yo'q:
Error konstruktori ikkinchi argument sifatida { cause } obyektini qabul qiladi: new Error("...", { cause: err }). Bu causeni saqlashning standart usuli. Yuqorida biz uni sodda ko'rinishda qo'lda o'rnatdik.ReadError) degan umumiy ma'lumotni oladi, kerak bo'lganda esa cause orqali chuqurroq kirib ko'radi.Xulosa
- O'z xatolarimizni
class MyError extends Errorko'rinishida yasaymiz; - Konstruktorda
super(message)ni chaqirish vathis.nameni belgilash shart; - Xatolarni
err instanceof MyErrororqali tekshiramiz โ u ota-klasslarni ham qamrab oladi; - Xatolardan ierarxiya (daraxt) yasash mumkin: aniqroq xatolar umumiyroqlaridan meros oladi;
this.name = this.constructor.namenomni avtomatik olishga yordam beradi;- Wrapping: past darajali xatolarni bitta umumiy xatoga o'rab, aslini
causeda saqlaymiz โ bu chaqiruvchi kodni soddalashtiradi.