Promise, async/await

Promise bilan xatoliklarni boshqarish

Asinxron ishlarda xatoliklar muqarrar: tarmoq uzilishi, noto'g'ri ma'lumot, server xatosi. Promise xatoliklarni boshqarishning ancha qulay yo'lini beradi. Ushbu darsda .catch, xatoning zanjir bo'ylab "sakrashi", qayta tashlash va e'tiborsiz qolgan rad etishlarni ko'rib chiqamiz.

.catch xatolikni ushlaydi

Promise zanjiri uzun bo'lsa ham, xatolikni boshqarish oson: zanjir oxiriga bitta .catch qo'yish kifoya. U zanjirning istalgan joyida yuz bergan xatolikni ushlaydi:

new Promise(function (resolve, reject) {
  setTimeout(function () {
    reject(new Error("Ma'lumot yuklanmadi!"));
  }, 1000);
})
  .then(function (result) {
    console.log(result); // ishlamaydi โ€” xato bo'ldi
  })
  .catch(function (error) {
    console.log("Xato ushlandi: " + error.message); // Xato ushlandi: Ma'lumot yuklanmadi!
  });

Reject bo'lgan Promise'da natija .thendan "sakrab o'tib", to'g'ridan-to'g'ri eng yaqin .catchga boradi.

Xatolik zanjir bo'ylab o'tishi

Xatoliklarni boshqarishdagi eng muhim tamoyil: reject (yoki tashlangan xato) zanjir bo'ylab eng yaqin .catchgacha "sakraydi". Oradagi barcha .thenlar o'tkazib yuboriladi.

new Promise(function (resolve, reject) {
  resolve(1);
})
  .then(function (result) {
    console.log("Bosqich 1: " + result); // 1
    throw new Error("Bosqich 1'da xato!"); // xato tashlaymiz
  })
  .then(function (result) {
    console.log("Bosqich 2"); // O'TKAZIB YUBORILADI
  })
  .then(function (result) {
    console.log("Bosqich 3"); // O'TKAZIB YUBORILADI
  })
  .catch(function (error) {
    console.log("Ushlandi: " + error.message); // Ushlandi: Bosqich 1'da xato!
  });
.then ichida throw qilingan xato ham, reject ham bir xil yo'l bilan boshqariladi โ€” ikkalasi ham Promise'ni rejected qiladi va keyingi .catchga uzatiladi. Ya'ni Promise ichidagi throw new Error(...) avtomatik reject(...)ga aylanadi.

Bu โ€” juda qulay xususiyat. Uzun zanjirda xatolik qayerda bo'lishidan qat'i nazar, uni bitta joyda โ€” oxirgi .catchda ushlaymiz. Callback'dagi kabi har bosqichda if (error) yozish shart emas.

.catch'dan keyin zanjir davom etadi

.catch xatoni ushlab, uni "tuzatgach", zanjir normal (fulfilled) holatda davom etadi. Chunki .catch ham Promise qaytaradi, va agar u xato tashlamasa, natija muvaffaqiyatli hisoblanadi:

new Promise(function (resolve, reject) {
  reject(new Error("Boshlang'ich xato"));
})
  .catch(function (error) {
    console.log("Xato tuzatildi: " + error.message);
    return "zaxira qiymat"; // xatoni "yamab", normal qiymat qaytaramiz
  })
  .then(function (result) {
    // Zanjir davom etadi โ€” endi normal holatda
    console.log("Davom: " + result); // Davom: zaxira qiymat
  });
Bu "xatodan tiklanish" (recovery) namunasi: xatolikni ushlab, o'rniga zaxira (fallback) qiymat berib, dasturni to'xtatmasdan davom ettirish mumkin.

Xatoni qayta tashlash (rethrowing)

Ba'zan .catch ichida xatoni ushlaymiz-u, lekin uni bartaraf eta olmaymiz โ€” masalan, kutilmagan boshqa turdagi xato. Bunday holda uni qayta tashlash (rethrow) mumkin, shunda u keyingi .catchga o'tadi:

new Promise(function (resolve, reject) {
  reject(new Error("Tarmoq xatosi"));
})
  .catch(function (error) {
    if (error.message === "Tarmoq xatosi") {
      console.log("Tarmoq xatosini boshqaramiz...");
      // bu xatoni hal qila olamiz โ€” davom etamiz
    } else {
      // hal qila olmaymiz โ€” qayta tashlaymiz
      throw error;
    }
  })
  .then(function () {
    console.log("Tarmoq xatosi hal qilingach bu ishlaydi");
  })
  .catch(function (error) {
    // Faqat qayta tashlangan (hal qilinmagan) xatolar bu yerga keladi
    console.log("Hal qilinmagan xato: " + error.message);
  });

Qoida sodda: agar .catch ichida throw qilsangiz โ€” nazorat keyingi .catchga o'tadi. Agar oddiy qaytsa (throw qilmasa) โ€” zanjir normal davom etadi. Bu try...catchning "agar hal qila olmasam, yuqoriga uzataman" tamoyiliga o'xshaydi.

Ishlov berilmagan rad etishlar (unhandledrejection)

Agar Promise reject bo'lsa-yu, uni ushlaydigan hech qanday .catch bo'lmasa nima bo'ladi? Xato "tiqilib" qoladi โ€” dastur bu haqda bilmay qoladi. Buni sezish uchun maxsus global hodisa bor: unhandledrejection.

// Bu Promise reject bo'ladi, ammo .catch YO'Q!
new Promise(function (resolve, reject) {
  reject(new Error("E'tiborsiz qolgan xato"));
});
// .then/.catch qo'shilmagan

// Brauzerda global hodisa ishga tushadi:
window.addEventListener("unhandledrejection", function (event) {
  console.log("Ishlov berilmagan rad etish!");
  console.log(event.promise); // muammoli Promise obyekti
  console.log(event.reason);  // xato obyekti (Error)
});

unhandledrejection hodisasi โ€” brauzer standartining bir qismi. U hech qayerda ushlanmagan Promise xatosi bo'lganda ishga tushadi. Hodisa obyektining ikki muhim xususiyati bor:

Node.js'da bu hodisa process.on("unhandledRejection", handler) orqali ushlanadi. Nomlanishi ozgina farq qiladi (bosh harflar), lekin g'oya bir xil.
Ishlov berilmagan rad etishlar โ€” jiddiy xato belgisidir. Ular odatda kodda unutilgan .catchni bildiradi. Har bir asinxron zanjir oxirida albatta .catch bo'lishini ta'minlang โ€” bu xatoni "yashirin" qolishidan saqlaydi.

Amaliy misol: xatoni ushlab, tiklanish

Sodda sinxron-o'xshash misol bilan "xato → catch → davom" oqimini mustahkamlaymiz. Bu yerda darhol reject bo'lgan Promise ishlatilgan, natija konsolda ko'rinadi:

promise-error.js
// natija shu yerda chiqadi

E'tibor bering: birinchi .catch xatoni ushlab, 42 qaytardi. Shundan so'ng zanjir normal davom etdi (42 → 50). Oxirgi .catch esa ishlamaydi, chunki hech qanday hal qilinmagan xato qolmadi.

Xulosa