Promise — asoslar, then, catch, finally

~20 daq · JavaScript · Asinxron JavaScript

Muammodan boshlaylik

Callback Hell da ko'rgan muammolarimiz:

  • Har qadam oldingi qadamning ichiga kiradi — piramida hosil bo'ladi
  • Xato boshqaruvi har qadamda takrorlanadi
  • Parallel so'rovlarni kutish — qo'lda flag, takror kod

Promise bu uchala muammoni hal qiladi. Avval Callback Hell ko'rinishi, keyin Promise bilan:

// Callback Hell — 4 qadam, 4 daraja chuqurlik
getUser(id, function(e, user) {
  getPosts(user.id, function(e, posts) {
    getComments(posts[0].id, function(e, comments) {
      render(user, posts, comments);
    });
  });
});

// Promise — 4 qadam, tekis zanjir
getUser(id)
  .then(user   => getPosts(user.id))
  .then(posts  => getComments(posts[0].id))
  .then(comments => render(comments))
  .catch(err   => xatoBoshqar(err));

Ikkinchisida piramida yo'q. Bitta .catch() barcha qadamlarning xatosini ushlaydi.


Promise nima?

Promise — "kelajakda qiymat bo'ladi" degan va'da. Hozir yo'q, lekin tayyor bo'lganda bildiriladi.

Hayotiy o'xshatma

Restorandagi buyurtma. Siz kelib: "bir porsiya lag'mon" dedingiz. Ofitsiant sizga chek berdi. Bu chek — va'da: "taom tayyor bo'lganda sizga olib kelamiz". Siz o'tirasiz, do'stingiz bilan gaplashasiz. Taom tayyor bo'lganda ofitsiant keltiradi. Agar mahsulot tugagan bo'lsa — kelib aytadi.

Chek — hozir taom emas. Lekin taom kelishiga ishonch. Kutish vaqtida siz boshqa narsalar qilasiz.

JavaScript da Promise — o'sha chek. Hozir qiymat yo'q, lekin kelajakda bo'ladi.


Promise ning uch holati

Promise yaratilganida — pending (kutilmoqda). Keyin ikki yo'nalishdan biri:

pending (kutilmoqda)
    │
    ├──→ fulfilled (muvaffaqiyatli) — .then() ishlaydi
    │
    └──→ rejected  (muvaffaqiyatsiz) — .catch() ishlaydi

Bir marta fulfilled yoki rejected bo'lgan Promise o'zgarmaydi. Restorandagi o'xshatma bilan: taom bir marta keldi — bo'ldi. Yoki "tugagan" deb aytildi — bo'ldi. Ikkinchi marta o'zgarmaydi.


Promise yaratish

const va_da = new Promise(function(resolve, reject) {
  // Bu yerda asinxron ish bajariladi

  const muvaffaqiyat = true;

  if (muvaffaqiyat) {
    resolve("Natija tayyor!");  // ← fulfilled
  } else {
    reject(new Error("Xato!"));  // ← rejected
  }
});

resolve — "va'da bajari ldi, mana natija". reject — "va'da bajarilmadi, mana sabab".


.then() — natija kelganda

.then() — Promise fulfilled bo'lganda ishlaydigan funksiya.

const va_da = new Promise(function(resolve) {
  setTimeout(function() {
    resolve({ ism: "Jasur", yosh: 25 });
  }, 1000); // 1 soniyadan keyin natija keladi
});

va_da.then(function(foydalanuvchi) {
  console.log(foydalanuvchi.ism); // "Jasur" — 1 soniyadan keyin
});

Zanjir — .then() dan .then() ga

.then() har doim yangi Promise qaytaradi. Bu tufayli zanjir hosil bo'ladi — bir .then() natijasi keyingi .then() ga o'tadi.

getUser(id)
  .then(function(user) {
    return getPosts(user.id); // ← yangi Promise qaytarildi
  })
  .then(function(posts) {
    // getPosts tugagandan keyingina shu yerga keladi
    return posts.filter(p => p.faol);
  })
  .then(function(faolPostlar) {
    console.log(faolPostlar);
  });

Nima uchun zanjir ishlaydi? .then() ichidan qaytarilgan narsa — keyingi .then() ning argumenti bo'ladi. Agar Promise qaytarilsa — u tugaguncha kutiladi.


.catch() — xato kelganda

.catch() — zanjirdagi istalgan joydan xato chiqsa, uni ushlaydi. Bitta .catch() barcha qadamlar uchun.

getUser(id)
  .then(user   => getPosts(user.id))
  .then(posts  => getComments(posts[0].id))
  .then(render)
  .catch(function(xato) {
    // Yuqoridagi istalgan qadamdan xato chiqsa — shu yerga tushadi
    console.error("Nimadir xato ketdi:", xato.message);
  });

Callback Hell da har qadamda if (xato) return; yozish kerak edi. Promise da — bir marta.


.finally() — xato bo'lsa ham, bo'lmasa ham

.finally() — natija qanday bo'lishidan qat'i nazar ishlaydigan funksiya. Tozalash ishlari uchun.

Hayotiy o'xshatma

Shifoxonaga operatsiya uchun kirdingiz. Operatsiya muvaffaqiyatli bo'lsa ham, bo'lmasa ham — operatsiya xonasini dezinfektsiya qilishadi. Bu ish har doim bajariladi, natijaga qarab emas.

let yuklanmoqda = true;

fetch("/api/users")
  .then(res  => res.json())
  .then(data => ko_rsat(data))
  .catch(err => xatoBoshqar(err))
  .finally(function() {
    yuklanmoqda = false;   // ← har holda yuklanish belgisi o'chiriladi
    spinner.hide();
  });

Promise.resolve va Promise.reject

Ba'zan darhol fulfilled yoki rejected Promise kerak:

Promise.resolve(42).then(n => console.log(n)); // 42 — darhol

Promise.reject(new Error("xato"))
  .catch(err => console.error(err.message));   // "xato" — darhol

Bu qachon kerak? Funksiya ba'zan keshlangan natijani sinxron qaytarsa, ba'zan serverdan asinxron olsa — ikkalasini bir xil ko'rinishga keltirish uchun:

function malumatOl(id) {
  const kesh = keshdan(id);
  if (kesh) {
    return Promise.resolve(kesh);  // ← darhol, keshdan
  }
  return serverdan(id);            // ← sekin, serverdan
}

// Ikkala holda ham .then() bilan ishlash mumkin
malumatOl(5).then(data => console.log(data));

Tez-tez uchraydigan xatolar

.then() da return unutish:

Bu eng ko'p chiqadigan xato. .then() ichida return yo'q bo'lsa — keyingi .then() undefined oladi.

getUser(id)
  .then(function(user) {
    getPosts(user.id); // ❌ return yo'q
  })
  .then(function(posts) {
    console.log(posts); // undefined — getPosts natijasi qaytarilmadi
  });

// ✅ return bilan
getUser(id)
  .then(function(user) {
    return getPosts(user.id); // ✅
  })
  .then(function(posts) {
    console.log(posts); // to'g'ri
  });

.catch() qo'ymaslik:

.catch() bo'lmasa — xato jimgina yo'qoladi. Konsol da "UnhandledPromiseRejection" ogohlantirmasi chiqadi, lekin kod ishlab ketaveradi — noto'g'ri holda.

fetch("/api")
  .then(res => res.json())
  .then(data => ko_rsat(data));
  // ❌ .catch() yo'q — xato bo'lsa bilinmaydi

// ✅
fetch("/api")
  .then(res => res.json())
  .then(data => ko_rsat(data))
  .catch(err => xatoBoshqar(err));

Xulosa

Promise — kelajakdagi qiymat uchun va'da. Uch holat: pending → fulfilled yoki rejected.

.then(fn) — muvaffaqiyatli natijada. Zanjir hosil qiladi.

.catch(fn) — xatoda. Zanjirdagi istalgan qadamning xatosini ushlaydi.

.finally(fn) — har holda. Tozalash ishlari uchun.

Callback Hell o'rniga — tekis zanjir. Bitta .catch() barcha xatolar uchun. Parallel so'rovlar uchun Promise.all — keyingi darslarda.


Keyingi dars

38-dars: Promise kombinatorlari — all, allSettled, race, any