Promise kombinatorlari — all, allSettled, race, any
Muammodan boshlaylik
Sahifani ochganda uchta alohida so'rov ketadi: foydalanuvchi ma'lumoti, uning postlari, bildirishnomalar. Ular bir-biriga bog'liq emas — birining natijasi ikkinchisiga kerak emas.
Siz .then() zanjiri bilan yozdingiz:
getUser()
.then(() => getPosts())
.then(() => getNotifs())
.then(() => render());
Ishlaydi. Lekin muammo bor. Har bir so'rov oldingi tugamasdan boshlanmaydi. getUser 300ms, getPosts 200ms, getNotifs 400ms — jami 900ms kutish.
Holbuki ularni bir vaqtda yuborsa bo'ladi. Jami kutish — eng uzuni kadar: 400ms.
Bir vaqtda bir nechta Promise boshqarish uchun — kombinatorlar.
Promise.all — hammasi muvaffaqiyatli bo'lsin
Promise.all — berilgan barcha Promise larni bir vaqtda boshlaydi. Hammasi tugagach, natijalarni massiv sifatida beradi.
Hayotiy o'xshatma
Oshxonada to'y taomi tayyorlanmoqda. Bir vaqtda: bir oshpaz osh qiladi, biri go'sht qiladi, biri salat qiladi. Hamma tayyor bo'lganda — dasturxon yoziladi. Bittasi kech qolsa — dasturxon kutadi. Biri umuman qila olmasa — to'y bekor bo'ladi.
Promise.all([
getUser(), // 300ms
getPosts(), // 200ms
getNotifs(), // 400ms
]).then(function([foydalanuvchi, postlar, bildirishnomalar]) {
// ← uchala tayyor bo'lgandan keyin — 400ms (eng uzuni)
render(foydalanuvchi, postlar, bildirishnomalar);
}).catch(function(xato) {
// ← istalgan biri xato bersa — darhol bu yerga
xatoBoshqar(xato);
});
Natijalar massivda — kirish tartibida. getUser tez tugasa ham, uning natijasi massivda birinchi o'rinda.
Qachon ishlatiladi?
Barcha natijalar kerak va bittasi muvaffaqiyatsiz bo'lsa — hammasi bekor bo'lishi kerak bo'lganda.
Promise.allSettled — hammasi tugasin, xato bo'lsa ham
Promise.all da bittasi xato bersa — qolganlarning natijasiga yetib bo'lmaydi. Ba'zan bu to'g'ri emas. Masalan: 10 ta xabar yuborildi, 2 tasi yetib bormadi — 8 tasining natijasini bilish kerak.
Promise.allSettled — barcha Promise lar tugaguncha kutadi. Xato bo'lsa ham to'xtatmaydi. Har birining holati qaytariladi.
Hayotiy o'xshatma
Pochta tarqatish. Pochtalyon 10 ta xat tarqatib chiqdi. Hammasi yetib bormasligi mumkin — kimsasiz uy, adres noto'g'ri. Lekin pochtalyon hamma xatni ko'rib chiqadi va hisobot tuzadi: "8 tasi yetdi, 2 tasi yetmadi". Bittasi yetmaganida qolganlarni tashlab ketmaydi.
Promise.allSettled([
fetch("/api/xabar/1"),
fetch("/api/xabar/2"),
fetch("/api/xabar/3"),
]).then(function(natijalar) {
natijalar.forEach(function(natija, i) {
if (natija.status === "fulfilled") {
console.log(`${i+1}-xabar yuborildi ✅`);
} else {
console.log(`${i+1}-xabar yuborilmadi ❌:`, natija.reason.message);
}
});
});
Har bir natijada status ("fulfilled" yoki "rejected") va qiymat yoki sabab bor.
Qachon ishlatiladi?
Natijalar mustaqil — bittasi xato bo'lsa ham qolganlarini bilish kerak bo'lganda.
Promise.race — birinchi tugagani g'alaba
Promise.race — berilgan Promise lardan birinchi tuganining natijasini qaytaradi. Muvaffaqiyatli ham, xato ham bo'lishi mumkin.
Hayotiy o'xshatma
Poygada birinchi finishga kirgan g'alaba qozonadi. Boshqalar hali yugurayotgan bo'lsa ham — birinchi yetib kelgan o'yinchi aniqlandi, poyga tugadi.
Promise.race ning eng ko'p ishlatiladigan holati — timeout: agar server ma'lum vaqt ichida javob bermasa, xato ko'rsatish.
function vaqtCheklangan(promise, ms) {
const timeout = new Promise(function(_, reject) {
setTimeout(function() {
reject(new Error(`${ms}ms dan oshdi`));
}, ms);
});
return Promise.race([promise, timeout]);
}
vaqtCheklangan(fetch("/api/sekin"), 3000)
.then(res => res.json())
.then(data => ko_rsat(data))
.catch(err => console.error(err.message));
// Agar 3 soniyada javob kelmasa: "3000ms dan oshdi"
Bu yerda ikkita Promise raqobatlashdi: haqiqiy so'rov va 3 soniyalik timeout. Qaysi biri birinchi tugasa — o'sha g'alaba qozonadi.
Qachon ishlatiladi?
Timeout qo'shish kerak bo'lganda yoki bir nechta manbadan eng tezini olish kerak bo'lganda.
Promise.any — birinchi muvaffaqiyatli
Promise.any — birinchi muvaffaqiyatli Promise qaytaradi. Xato bo'lgan Promise larga e'tibor bermaydi. Hammasi xato bo'lsagina — AggregateError qaytaradi.
Hayotiy o'xshatma
Uch xil taxi ilovasi bilan bir vaqtda mashina chaqirdingiz. Qaysi biri birinchi qabul qilsa — o'sha keladi. Boshqa ikkitasi rad etsa ham — bittasi qabul qilsa yetarli.
Promise.any([
fetch("https://server1.example.com/api"),
fetch("https://server2.example.com/api"),
fetch("https://server3.example.com/api"),
])
.then(res => res.json())
.then(data => ko_rsat(data))
.catch(err => console.error("Hamma server ishlamayapti"));
Agar server1 ishlamasa, server2 va server3 dan javob kutiladi. Birinchi ishlagan javob ishlatiladi.
race va any farqi
race — birinchi tugagani, xato bo'lsa ham. Agar birinchi tugagani xato bersa — catch ga tushadi.
any — birinchi muvaffaqiyatli. Xato berganlar e'tiborsiz qoladi, keyingilar kutiladi.
To'rttasini bir joyda taqqoslash
| Kombinator | Qachon tugaydi | Xatoda |
|---|---|---|
Promise.all |
hammasi fulfilled bo'lganda | birinchi xatoda darhol rejected |
Promise.allSettled |
hammasi tugaganda | hech qachon rejected — holat beriladi |
Promise.race |
birinchi tugaganda | birinchi xato ham rejected qiladi |
Promise.any |
birinchi fulfilled bo'lganda | hammasi xato bo'lsagina rejected |
Tez-tez uchraydigan xatolar
Promise.all da bittasi xato — boshqalarning natijasiga yeta olmaslik:
Ba'zan bir so'rov xato bersa ham, qolganlarini ko'rsatmoqchi bo'lasiz. Promise.all bunga imkon bermaydi — bittasi xato bersa hammasi yo'qoladi.
Yechim — har birining xatosini alohida ushlash:
Promise.all([
getUser().catch(() => null), // xato bo'lsa null
getPosts().catch(() => []), // xato bo'lsa bo'sh massiv
getNotifs().catch(() => []),
]).then(function([foydalanuvchi, postlar, bildirishnomalar]) {
if (!foydalanuvchi) showError("Foydalanuvchi yuklanmadi");
render(foydalanuvchi, postlar, bildirishnomalar);
});
Massiv o'rniga alohida argument berish:
// ❌ — Promise.all massiv kutadi
Promise.all(getUser(), getPosts()); // Xato: ikkinchi argument e'tiborsiz
// ✅
Promise.all([getUser(), getPosts()]);
Xulosa
To'rtta kombinator — to'rtta turli vaziyat uchun:
Promise.all — hammasi muvaffaqiyatli bo'lishi kerak. Bittasi xato — hammasi bekor.
Promise.allSettled — hammasi tugasin. Xato bo'lsa ham holati beriladi.
Promise.race — birinchi tugagani. Timeout qo'shish uchun.
Promise.any — birinchi muvaffaqiyatli. Zaxira serverlar uchun.
Keyingi dars
39-dars: Async/Await — asoslar