JavaScript'da xatolarni qanday to'g'ri qayta ishlash kerak?
Savol
try/catch/finally qanday ishlaydi, Errorning qanday o'rnatilgan subklasslari mavjud, o'zining xato klasslarini qanday yaratish kerak va asinxron koddagi hamda rad etilgan promise'lardagi xatolarni qanday ushlash mumkin?
Qisqa javob
try/catch/finally sinxron istisnolarni ushlaydi: xato bo'lsa catch bajariladi, finally esa natijadan qat'i nazar har doim bajariladi. Errorning o'rnatilgan subklasslari (TypeError, RangeError, ReferenceError va boshqalar) xatolarning aniq kategoriyalarini tasvirlaydi. O'z xatolari class MyError extends Error orqali yaratiladi. async/awaitdagi asinxron xatolar xuddi shu try/catch bilan ushlanadi, promise'larning ushlanmagan rad etilishlari esa .catch() yoki global unhandledrejection ishlovchisi orqali.
Batafsil javob
try/catch/finally. try bloki kodni bajaradi, catch(error) tashlangan istisnoni ushlaydi, finally har qanday holatda bajariladi — try yoki catch ichida return yoki yangi istisno bo'lsa ham. finally resurslarni kafolatli tozalash uchun foydali (ulanishlarni yopish, loader'larni olib tashlash). Muhim: try/catch faqat o'z blokidagi sinxron xatolarni ushlaydi — setTimeout ichida yoki try ichidagi qayta ishlanmagan promise'da tashlangan xato ushlanmaydi.
Error obyekti va uning subklasslari. Har bir xato message, name va stackka ega (chaqiruvlar trassirovkasi, spetsifikatsiyaga kirmaydi, lekin hamma joyda qo'llab-quvvatlanadi). O'rnatilgan subklasslar:
TypeError— mos kelmaydigan turdagi qiymat ustidan amal (null.foo, funksiya bo'lmagan narsani chaqirish).RangeError— ruxsat etilgan diapazondan tashqaridagi sonli qiymat (new Array(-1),toFixed(101)).ReferenceError— e'lon qilinmagan o'zgaruvchiga murojaat.SyntaxError— noto'g'ri sintaksis (odatdaeval/JSON.parseda).URIError—encodeURI/decodeURIfunksiyalaridagi xato.EvalError— eskirgan, deyarli uchramaydi.
Maxsus xatolar. class orqali Errordan meros olinadi, bu turli stsenariylarni (validatsiya, tarmoq, avtorizatsiya va h.k.) turlicha qayta ishlaydigan koddagi xato turlarini instanceof orqali ajratish imkonini beradi. super(message)ni chaqirish va this.nameni aniq belgilash muhim, aks holda name 'Error' bo'lib qoladi.
Asinxron koddagi xatolar:
async functionda har qanday istisno (shu jumladanthrowva rad etilganawait) rad etilgan promise'ga aylanadi vaawaitatrofidagi oddiytry/catchbilan ushlanadi.awaitsiz promise zanjirda.catch()talab qiladi — aks holdaunhandled promise rejectionolamiz.Promise.allbirinchi rad etishda butunlay yiqiladi — natijalar va xatolarni alohida yig'ish kerak bo'lsa,Promise.allSettledishlatiladi.- Promise'larning o'tkazib yuborilgan rad etilishlarini global tarzda brauzerda
window.addEventListener('unhandledrejection', ...)hodisasi orqali yoki Node.js'daprocess.on('unhandledRejection', ...)orqali ushlash mumkin — bu loglash uchun foydali, lekin mahalliy qayta ishlashning o'rnini bosmaydi.
Misol
// Bazaviy try/catch/finally
function parseConfig(json) {
try {
return JSON.parse(json)
} catch (error) {
console.error("Noto'g'ri JSON:", error.message) // SyntaxError
return null
} finally {
console.log('Parsing yakunlandi') // har qanday holatda bajariladi
}
}
// Error'ning o'rnatilgan subklasslari
try {
null.foo() // TypeError: Cannot read properties of null
} catch (e) {
console.log(e instanceof TypeError, e.name) // true "TypeError"
}
// Maxsus xato klassi
class ValidationError extends Error {
constructor(message, field) {
super(message)
this.name = 'ValidationError'
this.field = field
}
}
function validateAge(age) {
if (age < 0) {
throw new ValidationError("Yosh manfiy bo'lishi mumkin emas", 'age')
}
return age
}
try {
validateAge(-5)
} catch (error) {
if (error instanceof ValidationError) {
console.log(`"${error.field}" maydonida xato: ${error.message}`)
} else {
throw error // bu bizning xatomiz emas — yuqoriga uzatamiz
}
}
// Asinxron xatolar
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return await response.json()
} catch (error) {
console.error("Foydalanuvchini yuklab bo'lmadi:", error.message)
return null
}
}
// Promise.allSettled — birinchi xatoda yiqilmaydi
const results = await Promise.allSettled([
fetchUser(1),
fetchUser(-1), // aytaylik, rad etiladi
])
results.forEach((r) =>
r.status === 'fulfilled' ? console.log(r.value) : console.log('Xato:', r.reason)
)
Qo'shimcha savollar
- Xatolarni qayta ishlashda
Promise.allPromise.allSettledvaPromise.anydan nimasi bilan farq qiladi? new Error(message, { cause })dagicausexususiyati xatolar zanjirida qanday yordam beradi?- Nega ichida
returnbo'lganfinallytry/catchdagireturn/throwni "yopib qo'yishi" mumkin?