Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 1.1 Darsdagi yordamchi funksiya
- 2. Promise.all: hammasi yoki hech narsa
- 2.1 Natija — berilgan tartibda
- 2.2 Birinchi xatoda — darhol rad
- 2.3 Chegaraviy holatlar
- 3. Promise.allSettled: har birining taqdiri
- 3.1 Hech qachon rad etilmaydi
- 3.2 Muvaffaqiyatlilarni ajratish
- 4. Promise.race: birinchi hal bo'lgan yutadi
- 4.1 Poyga
- 4.2 Asosiy qo'llanishi: vaqt chegarasi
- 4.3 Tuzoq: taymerni tozalash
- 4.4 Bo'sh poyga
- 5. Promise.any: birinchi muvaffaqiyatli
- 5.1 Xatolarni o'tkazib yuboradi
- 5.2 Hammasi rad etilsa: AggregateError
- 6. Qaysi vaziyatda qaysi?
- 6.1 Taqqoslash jadvali
- 6.2 Hayotiy misollar
- 7. Ko'p uchraydigan xatolar
- 7.1 Promise o'rniga funksiya berish
- 7.2 Massivsiz chaqirish
- 7.3 allSettled natijasini tekshirmaslik
- 7.4 race ni "bekor qilish" deb o'ylash
- 7.5 any va race ni adashtirish
- 8. Mashqlar
- 1-mashq (oson): Natijani oldindan ayting
- 2-mashq (o'rta): Menyuni zaxira bilan olish
- 3-mashq (qiyin): O'z Promise.all ingiz
- 9. Real ishda
- Xulosa
- Manbalar
Promise kombinatorlari: Promise.all, allSettled, race va any
Qisqacha: To'rtta kombinator bir nechta Promise'ni bitta Promise'ga birlashtiradi, lekin har biri boshqa savolga javob beradi. Masalan,
Promise.all— "hammasi muvaffaqiyatli bo'ldimi?", birinchi xatoda rad etiladi;Promise.allSettled— "har biri qanday tugadi?", hech qachon rad etilmaydi. Poyga uchun ikkitasi bor:Promise.racebirinchi hal bo'lganini oladi (xato bo'lsa ham),Promise.anyesa birinchi muvaffaqiyatlisini. Hammasi rad etilsa,any—AggregateErrorberadi.
Bu darsda
Promise.allning natija tartibini, "birinchi xatoda rad" qoidasini va chegaraviy holatlarini aniq bilasiz.Promise.allSettledbilan har bir ishning natijasini — muvaffaqiyat ham, xato ham — yo'qotmasdan yig'asiz.Promise.racebilan vaqt chegarasi (timeout) yozasiz va uning tuzog'ini bilasiz.Promise.anyvaAggregateErrorni ishlatib, "birinchi muvaffaqiyatli javob" naqshini yozasiz.- Vaziyatga qarab to'rttasidan to'g'risini tanlay olasiz.
Oldin bilishingiz kerak: Promise asoslari, Promise zanjiri, async / await, Ketma-ket va parallel bajarish.
1. Nega bu kerak?
Callbacklar darsida ikki zaldan bo'sh stollarni bir vaqtda so'ragan edik. Buning uchun qoldi hisoblagichi, javoblar[indeks] va xato uchun yana bitta bayroq kerak bo'lgan edi. O'shanda "kombinatorlar buni bitta qator bilan bajaradi" degan edik. Ketma-ket va parallel bajarish darsida birinchisini — Promise.all ni — ko'rdingiz.
Lekin «Bahor»da parallel ishlar har xil bo'ladi va har biri boshqa savol beradi:
| Vaziyat | Savol |
|---|---|
| Stolga osh, salat va choy birga chiqadi | Hammasi tayyormi? Bittasi bo'lmasa — buyurtma bo'lmaydi |
| Kun oxirida uch filialdan hisobot | Har filial qanday tugatdi? Bittasi javob bermasa ham, qolganlari kerak |
| Oshxona javobini 1 soniyadan ko'p kutmaymiz | Nima birinchi bo'ldi: javobmi yoki muddat? |
| Uch zaldan bittasida joy topish kerak | Birinchi "joy bor" degan qaysi? |
To'rt savol — to'rt kombinator. Kombinator — bir nechta Promise'ni qabul qilib, ulardan bitta yangi Promise yasaydigan funksiya. Uning natijasi qachon va qanday hal bo'lishi — kombinatorning qoidasiga bog'liq.
Xuddi oshxonadagi to'rt xil ofitsiant kabi. Biri hamma taom tayyor bo'lishini kutadi. Ikkinchisi har taom haqida xabar yig'adi. Uchinchisi birinchi signal bilan yuguradi. To'rtinchisi birinchi tayyor taomni olib chiqadi.
1.1 Darsdagi yordamchi funksiya
Hamma misollarda oshxonani bitta funksiya bilan taqlid qilamiz — haqiqiy so'rov (fetch) fetch asoslari darsida keladi:
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (xato) {
reject(new Error(xato));
return;
}
console.log(` ${taom} tayyor`);
resolve(taom);
}, ms);
});
}
tayyorla("osh", 200).then((taom) => console.log("Keldi:", taom));Konsolda:
osh tayyor
Keldi: oshtayyorla ms millisekunddan keyin taomni beradi va "tayyor" deb yozadi. Uchinchi argument — xato matni — berilsa, Promise shu matnli xato bilan rad etiladi. "Tayyor" yozuvlari ikki bo'shliq bilan surilgan: ular oshxona ichida bo'layotgan ishni ko'rsatadi.
2. Promise.all: hammasi yoki hech narsa
2.1 Natija — berilgan tartibda
Promise.all(promiselar) — massivdagi hamma Promise bajarilishini kutadi va natijalarni massiv qilib beradi. Uni avvalgi darsdan bilasiz. Bugun uni oxirigacha ochamiz:
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (xato) {
reject(new Error(xato));
return;
}
console.log(` ${taom} tayyor`);
resolve(taom);
}, ms);
});
}
async function stolgaChiqar() {
const taomlar = await Promise.all([
tayyorla("osh", 300),
tayyorla("salat", 100),
tayyorla("choy", 200),
]);
console.log("Stolga:", taomlar.join(", "));
}
stolgaChiqar();Konsolda:
salat tayyor
choy tayyor
osh tayyor
Stolga: osh, salat, choyIkki narsaga qarang. Taomlar har xil tartibda tayyor bo'ldi: salat, choy, osh. Natija massivi esa berilgan tartibda: osh, salat, choy. Promise.all har natijani o'z o'rniga qo'yadi — xuddi Callbacklar darsidagi javoblar[indeks] kabi. Shuning uchun taomlar[0] doim osh, kim birinchi tayyor bo'lishidan qat'i nazar.
Umumiy vaqt — eng sekin ish vaqti, ya'ni taxminan 300 ms. Ketma-ket await bilan 600 ms bo'lardi.
2.2 Birinchi xatoda — darhol rad
Endi salat uchun pomidor tugagan:
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (xato) {
reject(new Error(xato));
return;
}
console.log(` ${taom} tayyor`);
resolve(taom);
}, ms);
});
}
async function stolgaChiqar() {
try {
const taomlar = await Promise.all([
tayyorla("osh", 300),
tayyorla("salat", 100, "Pomidor tugadi"),
tayyorla("choy", 200),
]);
console.log("Stolga:", taomlar.join(", "));
} catch (xato) {
console.log("Buyurtma bajarilmadi:", xato.message);
}
}
stolgaChiqar();Konsolda:
Buyurtma bajarilmadi: Pomidor tugadi
choy tayyor
osh tayyorSalat 100 ms da rad etildi va shu zahoti Promise.all ham rad etildi — choy va oshni kutmadi. Bu qoida fail-fast ("tez yiqilish") deb ataladi: natija baribir bo'lmasa, kutishdan foyda yo'q. Xato catch ga birinchi rad etilgan Promise'ning xatosi sifatida keladi.
Lekin pastki ikki qatorga qarang. "Buyurtma bajarilmadi" dan keyin ham choy va osh tayyor bo'ldi. Qadamma-qadam ko'ramiz:
Bu muhim farq: Promise.all kutishni to'xtatadi, ishlarni emas. Promise — faqat natija uchun "chipta", u ishni boshqarmaydi. Oshpaz osh pishirishda davom etadi. Haqiqiy so'rovlarni to'xtatish uchun boshqa vosita kerak — AbortController darsida ko'ramiz.
2.3 Chegaraviy holatlar
Uchta kichik, lekin intervyuda so'raladigan detal. Kodda bitta yangi yozuv bor: Promise.resolve(28000) — new Promise((resolve) => resolve(28000)) ning qisqa shakli, ya'ni darhol bajarilgan Promise. Uni keyingi darsda, Promise yordamchilari da to'liq ko'ramiz.
async function sinab() {
const bosh = await Promise.all([]);
console.log(bosh);
const aralash = await Promise.all([35000, Promise.resolve(28000)]);
console.log(aralash);
const toplam = new Set([Promise.resolve("osh")]);
console.log(await Promise.all(toplam));
}
sinab();Konsolda:
[]
[ 35000, 28000 ]
[ 'osh' ]- Bo'sh massiv — darhol
[]bilan bajariladi. Kutadigan narsa yo'q — demak "hammasi tayyor". - Promise bo'lmagan qiymat (
35000) — tayyor natija deb qabul qilinadi va o'z o'rniga qo'yiladi. - Massiv shart emas — har qanday iterable bo'ladi:
Set,Mapningvalues(), generator (Iterable va iterator protokoli). Natija esa doim massiv.
Tekshirib ko'ring:
Promise.all([tayyorla("osh", 500), tayyorla("choy", 100, "Choy tugadi")])taxminan necha millisekundda va qanday tugaydi? Osh tayyor bo'ladimi?
Javob
Taxminan 100 ms da, "Choy tugadi" xatosi bilan rad etiladi — fail-fast. Osh baribir 500 ms da tayyor bo'ladi va "osh tayyor" deb yozadi: Promise.all ishni to'xtatmaydi, faqat uning natijasini kutmay qo'yadi.
3. Promise.allSettled: har birining taqdiri
3.1 Hech qachon rad etilmaydi
Kun oxirida «Bahor»ning uch filialidan bugungi tushum so'raladi. Yunusobod filiali javob bermadi. Promise.all bo'lganida qolgan ikkitasining raqami ham yo'qolardi. Hisobotga esa hammasi kerak: kim qancha topdi va kim javob bermadi.
Promise.allSettled(promiselar) — hamma Promise hal bo'lishini (settled — bajarildi yoki rad etildi) kutadi. U hech qachon rad etilmaydi. Natija — har Promise uchun bitta hisobot obyekti:
- bajarilgan bo'lsa —
{ status: "fulfilled", value: natija }; - rad etilgan bo'lsa —
{ status: "rejected", reason: xato }.
function tushumniSora(filial, ms, summa) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (summa === undefined) {
reject(new Error(`${filial}: aloqa yo'q`));
return;
}
resolve(summa);
}, ms);
});
}
async function hisobotTuz() {
const filiallar = ["Chilonzor", "Yunusobod", "Sergeli"];
const natijalar = await Promise.allSettled([
tushumniSora("Chilonzor", 200, 4_200_000),
tushumniSora("Yunusobod", 100),
tushumniSora("Sergeli", 300, 3_100_000),
]);
console.log(natijalar.map((n) => n.status));
let jami = 0;
natijalar.forEach((natija, i) => {
if (natija.status === "fulfilled") {
jami += natija.value;
console.log(`${filiallar[i]}: ${natija.value} so'm`);
} else {
console.log(`${filiallar[i]}: ${natija.reason.message}`);
}
});
console.log("Jami:", jami);
}
hisobotTuz();Konsolda:
[ 'fulfilled', 'rejected', 'fulfilled' ]
Chilonzor: 4200000 so'm
Yunusobod: Yunusobod: aloqa yo'q
Sergeli: 3100000 so'm
Jami: 7300000Yunusobod 100 ms da rad etildi, lekin allSettled kutishda davom etdi va 300 ms da — oxirgi filial javob bergach — hisobotni berdi. Natijalar ham Promise.all dagidek berilgan tartibda.
E'tibor bering: try/catch kerak bo'lmadi. allSettled ning o'zi rad etilmaydi — xatolar natija ichida, reason maydonida keladi. Shuning uchun har natijaning status ini tekshirish sizning vazifangiz.
3.2 Muvaffaqiyatlilarni ajratish
Ko'pincha natijalarni ikki guruhga ajratish kerak bo'ladi — filter va map bilan:
const natijalar = [
{ status: "fulfilled", value: 4_200_000 },
{ status: "rejected", reason: new Error("aloqa yo'q") },
{ status: "fulfilled", value: 3_100_000 },
];
const summalar = natijalar
.filter((n) => n.status === "fulfilled")
.map((n) => n.value);
const xatolar = natijalar
.filter((n) => n.status === "rejected")
.map((n) => n.reason.message);
console.log(summalar); // [ 4200000, 3100000 ]
console.log(xatolar); // [ "aloqa yo'q" ]Bu yerda natijalarni qo'lda yozdik — allSettled aynan shunday massiv beradi. Node satrni odatda '...' ichida ko'rsatadi, lekin satrning o'zida ' bo'lsa — "..." ichida. Ma'nosi bir xil.
Promise.allSettled ES2020 da qo'shilgan; Baseline ma'lumotiga ko'ra 2020-yil iyulidan hamma asosiy brauzerda bor.
Tekshirib ko'ring:
Promise.allSettledga berilgan uchala Promise ham rad etilsa,await Promise.allSettled(...)qatori xato tashlaydimi?
Javob
Yo'q. allSettled hech qachon rad etilmaydi. U uchta { status: "rejected", reason: ... } obyektli massiv bilan bajariladi. Xatoni bilish uchun status ni o'zingiz tekshirasiz.
4. Promise.race: birinchi hal bo'lgan yutadi
4.1 Poyga
Promise.race(promiselar) — birinchi hal bo'lgan Promise'ning natijasini oladi. Birinchi bo'lib bajarilgan bo'lsa — o'sha qiymat bilan bajariladi. Birinchi bo'lib rad etilgan bo'lsa — o'sha xato bilan rad etiladi. "Race" — inglizcha "poyga".
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (xato) {
reject(new Error(xato));
return;
}
console.log(` ${taom} tayyor`);
resolve(taom);
}, ms);
});
}
async function poyga() {
const birinchi = await Promise.race([
tayyorla("osh", 300),
tayyorla("somsa", 100),
]);
console.log("Birinchi chiqdi:", birinchi);
try {
await Promise.race([
tayyorla("manti", 300),
tayyorla("lag'mon", 100, "Xamir tugadi"),
]);
} catch (xato) {
console.log("Poyga xato bilan tugadi:", xato.message);
}
}
poyga();Konsolda:
somsa tayyor
Birinchi chiqdi: somsa
Poyga xato bilan tugadi: Xamir tugadi
osh tayyor
manti tayyorBirinchi poygada somsa yutdi. Ikkinchisida lag'mon birinchi rad etildi — va race ham rad etildi, garchi manti muvaffaqiyatli tayyor bo'lsa ham. race uchun muvaffaqiyat yoki xato — farqi yo'q, faqat kim birinchi. Yutqazganlar esa Promise.all dagidek ishlashda davom etadi: osh ham, manti ham tayyor bo'ldi.
4.2 Asosiy qo'llanishi: vaqt chegarasi
race ning eng ko'p uchraydigan ishi — vaqt chegarasi (timeout): "javob 1 soniyada kelmasa, kutmayman". Ishni muddat bilan poygaga qo'yamiz. Muddat — belgilangan vaqtda rad etiladigan Promise:
function tayyorla(taom, ms) {
return new Promise((resolve) => {
setTimeout(() => resolve(taom), ms);
});
}
function muddatBilan(promise, ms) {
let taymer;
const muddat = new Promise((resolve, reject) => {
taymer = setTimeout(() => {
reject(new Error(`${ms} ms da javob kelmadi`));
}, ms);
});
return Promise.race([promise, muddat]).finally(() => {
clearTimeout(taymer);
});
}
async function buyurtmaBer(taom, ms) {
try {
const natija = await muddatBilan(tayyorla(taom, ms), 250);
console.log("Olib chiqildi:", natija);
} catch (xato) {
console.log(`${taom}: ${xato.message}`);
}
}
async function sinab() {
await buyurtmaBer("somsa", 100);
await buyurtmaBer("osh", 400);
}
sinab();Konsolda:
Olib chiqildi: somsa
osh: 250 ms da javob kelmadiKod qanday ishlaydi: muddat — ms dan keyin rad etiladigan Promise. Keyin race ish va muddatni poygaga qo'yadi. Somsa 100 ms da keldi — ish yutdi. Osh 400 ms oladi — muddat (250 ms) yutdi. Ikkala holatda ham finally taymerni tozalaydi. O'zgaruvchi taymer executor'dan tashqarida e'lon qilingan, chunki finally ichida ham unga yetish kerak.
Callbacklar darsining 3-mashqida xuddi shu nomli muddatBilan ni yozgan edingiz — u yerda tugadi bayrog'i va birMarta himoyasi kerak edi. Promise'da ular kerak emas: Promise bir marta hal bo'ladi, keyingi resolve/reject chaqiruvlari e'tiborsiz qoladi (Promise asoslari).
4.3 Tuzoq: taymerni tozalash
finally dagi clearTimeout ni olib tashlasangiz, somsa misoli ham to'g'ri chiqadi. Lekin muddat taymeri 250 ms gacha "osilib" qoladi. Shu vaqtda u:
- Node'da dasturning tugashini kechiktiradi — Node faol taymer bor ekan, jarayonni yopmaydi;
rejectni chaqiradi — natija hech kimga kerak emas, lekin ish bajariladi.
Bitta so'rovda bu sezilmaydi. Sekundiga yuzlab so'rov qabul qiladigan serverda esa minglab ortiqcha taymer to'planadi. Qoida: poygaga qo'ygan taymeringizni o'zingiz tozalang. Brauzer va Node'da buning tayyor vositasi ham bor — AbortSignal.timeout(ms) — uni AbortController darsida ko'ramiz.
4.4 Bo'sh poyga
Promise.race([]) hech qachon hal bo'lmaydi — u abadiy kutish holatida qoladi. Poygachi yo'q — g'olib ham yo'q. Massiv dinamik yig'ilsa (masalan filter dan keyin), bo'sh bo'lib qolmasligini tekshiring: aks holda await abadiy kutadi va xato ham chiqmaydi.
Tekshirib ko'ring:
muddatBilan(tayyorla("osh", 100, "Guruch tugadi"), 250)nima bilan tugaydi: "Guruch tugadi" bilanmi yoki "250 ms da javob kelmadi" bilanmi?
Javob
"Guruch tugadi" bilan, taxminan 100 ms da. race birinchi hal bo'lganini oladi — rad etilish ham hal bo'lish. Muddat Promise'i 250 ms da hal bo'lardi, lekin finally ichidagi clearTimeout uni bekor qiladi.
5. Promise.any: birinchi muvaffaqiyatli
5.1 Xatolarni o'tkazib yuboradi
Dilshod aka 6 kishilik stol so'radi. Uch zal bor — ichki zal, ayvon va yozgi supa. Qaysi biri birinchi "joy bor" desa — o'sha yerga bron qilamiz. "Joy yo'q" javoblari bizni qiziqtirmaydi.
race bu yerda yaramaydi: birinchi bo'lib "joy yo'q" kelsa, race shu xato bilan tugaydi. Bizga birinchi muvaffaqiyatli javob kerak.
Promise.any(promiselar) — birinchi bajarilgan Promise'ning qiymatini oladi. Rad etilganlarni e'tiborsiz qoldiradi va keyingisini kutadi:
function stolSora(zal, ms, bormi) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (bormi) {
resolve(`${zal}: 6 kishilik stol bor`);
} else {
reject(new Error(`${zal}: joy yo'q`));
}
}, ms);
});
}
async function stolTop() {
const javob = await Promise.any([
stolSora("ichki zal", 100, false),
stolSora("ayvon", 300, true),
stolSora("yozgi supa", 200, true),
]);
console.log("Bron:", javob);
}
stolTop();Konsolda:
Bron: yozgi supa: 6 kishilik stol borIchki zal 100 ms da "joy yo'q" dedi — any e'tibor bermadi. Yozgi supa 200 ms da "bor" dedi — any shu javob bilan bajarildi. Ayvon javobi (300 ms) kerak bo'lmadi.
5.2 Hammasi rad etilsa: AggregateError
Uchala zal ham to'la bo'lsa-chi? any qaysi xatoni berishi kerak — birinchisinimi, oxirgisinimi? Hech birini emas: u hamma xatoni bitta obyektga yig'adi.
AggregateError ("yig'ma xato") — bir nechta xatoni errors massivida saqlaydigan xato turi. Stack trace va JavaScript xato turlari darsida "uni haqiqiy chiqishda ko'rasiz" degan edik. Mana u:
function stolSora(zal, ms) {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`${zal}: joy yo'q`)), ms);
});
}
async function stolTop() {
try {
await Promise.any([
stolSora("ichki zal", 100),
stolSora("ayvon", 300),
stolSora("yozgi supa", 200),
]);
} catch (xato) {
console.log(xato.name);
console.log(xato.message);
console.log(xato.errors.map((x) => x.message));
}
}
stolTop();Konsolda:
AggregateError
All promises were rejected
[ "ichki zal: joy yo'q", "ayvon: joy yo'q", "yozgi supa: joy yo'q" ]All promises were rejected — "hamma Promise'lar rad etildi". errors massividagi xatolar ham berilgan tartibda, rad etilish vaqti tartibida emas: ayvon 300 ms da oxirgi bo'lib rad etildi, lekin massivda ikkinchi.
Agar catch bo'lmasa, Node 24 dasturni to'xtatadi va terminalda xato [AggregateError: All promises were rejected] { qatori bilan boshlanadi. Uning ichida [errors]: [ ro'yxati va har xatoning stack trace'i keladi.
Promise.any([]) — bo'sh massiv — darhol AggregateError bilan rad etiladi: muvaffaqiyatli bo'ladigan birorta ham Promise yo'q.
Promise.any va AggregateError ES2021 da qo'shilgan; Baseline ma'lumotiga ko'ra 2020-yil sentyabridan hamma asosiy brauzerda bor.
Tekshirib ko'ring:
Promise.any([tayyorla("osh", 300), tayyorla("choy", 100, "Choy tugadi")])nima bilan tugaydi?Promise.racebilan-chi?
Javob
any — 300 ms da "osh" bilan bajariladi: choyning xatosi o'tkazib yuboriladi. race — 100 ms da "Choy tugadi" xatosi bilan rad etiladi: u birinchi hal bo'lganini oladi, xato bo'lsa ham.
6. Qaysi vaziyatda qaysi?
6.1 Taqqoslash jadvali
To'rttasi bir xil shaklda chaqiriladi, lekin qoidalari har xil:
| Kombinator | Qachon bajariladi | Qachon rad etiladi |
|---|---|---|
Promise.all |
hammasi bajarilsa → qiymatlar massivi | birinchi rad etilishda |
Promise.allSettled |
hammasi hal bo'lsa → hisobotlar massivi | hech qachon |
Promise.race |
birinchi hal bo'lgan bajarilsa | birinchi hal bo'lgan rad etilsa |
Promise.any |
birinchi bajarilganda | hammasi rad etilsa → AggregateError |
Bo'sh massiv bilan ham xulqi har xil: all va allSettled darhol [] beradi, any darhol AggregateError, race esa abadiy kutadi.
Hayotiy savollar bilan bog'lasak — shunday tanlash sxemasi chiqadi:
flowchart TD
S{"Hamma natija<br/>kerakmi?"}
S -- "ha" --> X{"Bitta xato hammasini<br/>buzadimi?"}
X -- "ha" --> A["Promise.all"]
X -- "yo'q" --> B["Promise.allSettled"]
S -- "yo'q, bittasi yetadi" --> Y{"Xato javob ham<br/>javobmi?"}
Y -- "ha, kim birinchi" --> C["Promise.race"]
Y -- "yo'q, muvaffaqiyatli kerak" --> D["Promise.any"]6.2 Hayotiy misollar
all— sahifa uchun menyu, foydalanuvchi va savat birga kerak; bittasisiz sahifani ko'rsatib bo'lmaydi. Yoki 10 ta rasmni yuklash, keyin galereyani chizish.allSettled— bir nechta mustaqil ish: 50 ta mijozga SMS yuborish va "45 ta yuborildi, 5 ta xato" hisoboti. Yoki boshqaruv panelidagi vidjetlar: biri yuklanmasa, qolganlari ko'rinaversin.race— vaqt chegarasi. Yoki "eng tez javob bergan" holati, xato ham javob hisoblanganda.any— bir xil ma'lumotning bir nechta manbasi (zaxira serverlar, CDN'lar): qaysi biri birinchi muvaffaqiyatli bersa, o'sha.
Tekshirib ko'ring: Ro'yxatdan o'tishda ikki tekshiruv parallel bajariladi: "login band emasmi?" va "email band emasmi?". Ikkalasi ham o'tishi shart. Qaysi kombinator?
Javob
Promise.all. Ikkala natija ham kerak va bittasi muvaffaqiyatsiz bo'lsa, ro'yxatdan o'tish baribir bo'lmaydi — ikkinchisini kutishning ma'nosi yo'q (fail-fast). Agar foydalanuvchiga ikkala xatoni birdan ko'rsatmoqchi bo'lsangiz ("login ham, email ham band") — allSettled.
7. Ko'p uchraydigan xatolar
7.1 Promise o'rniga funksiya berish
function tayyorla(taom) {
return new Promise((resolve) => setTimeout(resolve, 100, taom));
}
async function sinab() {
const xato = await Promise.all([tayyorla, tayyorla]);
console.log(xato);
const togri = await Promise.all([
tayyorla("osh"),
tayyorla("choy"),
]);
console.log(togri);
}
sinab();Konsolda:
[ [Function: tayyorla], [Function: tayyorla] ]
[ 'osh', 'choy' ]Birinchi qatorda funksiyalar chaqirilmagan — Promise.all ularni oddiy qiymat deb qabul qildi va xatosiz qaytardi. Hech qanday ish bajarilmadi. Kombinatorlar Promise'larni kutadi, ishni boshlamaydi. Ishni siz boshlaysiz — tayyorla("osh") chaqiruvi bilan.
7.2 Massivsiz chaqirish
const osh = Promise.resolve("osh");
const choy = Promise.resolve("choy");
Promise.all(osh, choy).then((taomlar) => console.log(taomlar));TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))"Obyekt iterable emas ('Symbol.iterator' xususiyatini o'qib bo'lmadi)". Kombinator bitta argument kutadi — iterable (odatda massiv). osh Promise'i iterable emas, choy esa umuman e'tiborsiz qoldi. Xabardagi Symbol.iterator — iteratsiya protokoli dagi kalit: JavaScript argumentni aylanib chiqmoqchi bo'ldi. Tuzatish — kvadrat qavslar: Promise.all([osh, choy]).
7.3 allSettled natijasini tekshirmaslik
allSettled rad etilmagani uchun "hammasi joyida" deb o'ylash oson. natijalar.map((n) => n.value) yozsangiz, rad etilganlar o'rnida undefined chiqadi — xato jim yo'qoladi. Har doim status ga qarang.
7.4 race ni "bekor qilish" deb o'ylash
race yoki all ning rad etilishi yutqazgan ishlarni to'xtatmaydi — buni bugun uch marta ko'rdik. Oshxona ortiqcha osh pishiradi, server ortiqcha so'rovni bajaradi. Haqiqiy to'xtatish — AbortController.
7.5 any va race ni adashtirish
Ikkalasi ham "birinchi"ni oladi. Farqi — xatoga munosabatda. Zaxira manbalar uchun race ishlatilsa, birinchi bo'lib tez rad etilgan manba hammasini buzadi. Qoida: "xato ham javob" — race, "menga natija kerak" — any.
8. Mashqlar
1-mashq (oson): Natijani oldindan ayting
Uchta Promise bor: a — 300 ms da "osh" bilan bajariladi, b — 100 ms da "Choy tugadi" xatosi bilan rad etiladi, c — 200 ms da "somsa" bilan bajariladi. Har kombinator nima beradi?
Promise.all([a, b, c])— rad etiladi, xabari:Promise.race([a, b, c])— rad etiladi, xabari:Promise.any([a, b, c])— bajariladi, qiymati:Promise.allSettled([a, b, c])— ikkinchi hisobotningstatusi:
Yechim
all— birinchi rad etilish 100 ms da: "Choy tugadi". Fail-fast.race— birinchi hal bo'lgan hamb: u rad etilgan, demakraceham "Choy tugadi" bilan rad etiladi.any— rad etilganbo'tkazib yuboriladi, birinchi bajarilgan —c(200 ms): "somsa".allSettled— hisobotlar berilgan tartibda:fulfilled,rejected,fulfilled. Ikkinchisi —rejected.
Tekshirish uchun kod:
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
xato ? reject(new Error(xato)) : resolve(taom);
}, ms);
});
}
function uchta() {
return [
tayyorla("osh", 300),
tayyorla("choy", 100, "Choy tugadi"),
tayyorla("somsa", 200),
];
}
async function tekshir() {
await Promise.all(uchta())
.catch((x) => console.log("all:", x.message));
await Promise.race(uchta())
.catch((x) => console.log("race:", x.message));
console.log("any:", await Promise.any(uchta()));
const hisobot = await Promise.allSettled(uchta());
console.log("allSettled:", hisobot[1].status);
}
tekshir();Konsolda:
all: Choy tugadi
race: Choy tugadi
any: somsa
allSettled: rejecteduchta() har safar yangi Promise'lar yaratadi. Bitta massivni to'rt marta bersak, ular allaqachon hal bo'lgan bo'lardi va vaqtlar tekshirilmasdi. xato ? ... : ... — ternary operator.
2-mashq (o'rta): Menyuni zaxira bilan olish
«Bahor» menyusini uch manbadan olish mumkin: asosiy server (sekin, ba'zan ishlamaydi), zaxira server va keshdagi nusxa. menyuniOl(manbalar) funksiyasini yozing:
- birinchi muvaffaqiyatli manbaning menyusini qaytarsin;
- hamma manba xato bersa —
"Menyu hozircha mavjud emas"matnini qaytarsin va har xatoniconsole.logbilan chiqarsin.
Manbani manba(nom, ms, menyu) bilan taqlid qiling: menyu berilmasa — ${nom} ishlamayapti xatosi bilan rad etilsin. Ishora: Promise.any va catch ichida xato.errors.
Yechim
function manba(nom, ms, menyu) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (menyu) {
resolve(`${nom}: ${menyu.join(", ")}`);
} else {
reject(new Error(`${nom} ishlamayapti`));
}
}, ms);
});
}
async function menyuniOl(manbalar) {
try {
return await Promise.any(manbalar);
} catch (xato) {
for (const x of xato.errors) {
console.log(" -", x.message);
}
return "Menyu hozircha mavjud emas";
}
}
async function sinab() {
console.log(await menyuniOl([
manba("asosiy server", 300),
manba("zaxira server", 200, ["osh", "manti"]),
manba("kesh", 50, ["osh"]),
]));
console.log(await menyuniOl([
manba("asosiy server", 100),
manba("zaxira server", 150),
]));
}
sinab();Konsolda:
kesh: osh
- asosiy server ishlamayapti
- zaxira server ishlamayapti
Menyu hozircha mavjud emasBirinchi chaqiruvda kesh eng tez (50 ms) va muvaffaqiyatli — any uni oldi. Ikkinchisida ikkala manba ham rad etildi — AggregateError ning errors massivi ikkala sababni ham saqladi.
return await — try ichida muhim: await siz return Promise.any(...) yozilsa, rad etilish try/catch dan o'tib ketadi va catch ishlamaydi. Bu — async / await darsidagi «return va return await farqi».
3-mashq (qiyin): O'z Promise.all ingiz
Kombinator ichida sehr yo'q — Callbacklar darsidagi qoldi hisoblagichi g'oyasi. hammasi(promiselar) funksiyasini yozing — Promise.all ning soddalashtirilgan nusxasi:
new Promiseqaytarsin;- natijalar berilgan tartibda bo'lsin (
natijalar[i] = qiymat); - birinchi xatoda —
reject; - bo'sh massiv — darhol
[]; - Promise bo'lmagan qiymat ham ishlasin — uni
Promise.resolve(qiymat)bilan o'rang («Chegaraviy holatlar» bo'limida ko'rdik). Promise bersangiz, u o'shaning o'zini qaytaradi — shuning uchun hamma elementni bemalol o'rash mumkin.
kurs/mashqlar/11/09-kombinatorlar/hammasi.mjs ga saqlang va Promise.all bilan bir xil natija berishini tekshiring.
Yechim
function hammasi(promiselar) {
return new Promise((resolve, reject) => {
const natijalar = [];
let qoldi = promiselar.length;
if (qoldi === 0) {
resolve(natijalar);
return;
}
promiselar.forEach((p, i) => {
Promise.resolve(p).then((qiymat) => {
natijalar[i] = qiymat;
qoldi--;
if (qoldi === 0) {
resolve(natijalar);
}
}, reject);
});
});
}
function tayyorla(taom, ms, xato) {
return new Promise((resolve, reject) => {
setTimeout(() => {
xato ? reject(new Error(xato)) : resolve(taom);
}, ms);
});
}
async function sinab() {
console.log(await hammasi([
tayyorla("osh", 300),
35000,
tayyorla("choy", 100),
]));
console.log(await hammasi([]));
try {
await hammasi([
tayyorla("osh", 300),
tayyorla("choy", 100, "Tugadi"),
]);
} catch (xato) {
console.log("Rad:", xato.message);
}
}
sinab();Konsolda:
[ 'osh', 35000, 'choy' ]
[]
Rad: TugadiKalit joylar:
natijalar[i] = qiymat—pushemas.pushkelish tartibida yozardi: choy oshdan oldin.then(qiymat => ..., reject)—thenning ikkinchi argumenti rad etilishda chaqiriladi. Birinchi xatorejectni chaqiradi. Keyingi xatolar hamrejectni chaqiradi, lekin Promise bir marta hal bo'ladi — ular e'tiborsiz qoladi. Callbacklar darsidagi "xato bayrog'i" kerak emas.- Haqiqiy
Promise.allhar qanday iterable'ni qabul qiladi; biznikidaforEachbor — faqat massiv. Bu soddalashtirish.
git add 11/09-kombinatorlar/hammasi.mjs
git commit -m "11/09: o'z Promise.all nusxasi"9. Real ishda
- Sahifa yuklanishi. Frontend'da sahifa ochilganda bir nechta so'rov parallel yuboriladi va
Promise.allbilan kutiladi. React'dagi ma'lumot yuklovchi kutubxonalar (TanStack Query va boshqalar) ichida ham shu g'oya bor — React va ularni kursning keyingi qismlarida o'rganamiz, hozir bilish shart emas. - Ommaviy amallar. Yuzlab foydalanuvchiga xabar yuborish, fayllarni qayta ishlash —
allSettledva keyin "nechta muvaffaqiyatli, nechta xato" hisoboti. Bir mijozning xatosi qolganlarni to'xtatmasligi kerak. - Vaqt chegarasi. Har tashqi so'rovga muddat qo'yish — production'ning qat'iy qoidasi.
racebilan qo'lda yokiAbortSignal.timeoutbilan. - Parallellik cheklovi.
Promise.allga 10 000 ta so'rovni birdan berish serverni "bo'g'ib" qo'yadi. Bir vaqtda faqat 5 tadan bajarish naqshini Asinxron naqshlar darsida yozamiz. - Intervyu. "
Promise.allvaallSettledfarqi?", "racevaanyfarqi?", "Promise.allni o'zingiz yozing" — eng ko'p so'raladigan asinxron savollar. 3-mashq aynan shu.
Xulosa
- Kombinator bir nechta Promise'dan bitta Promise yasaydi; natija massivlari doim berilgan tartibda.
Promise.all— hammasi kerak; birinchi xatoda darhol rad etiladi (fail-fast).Promise.allSettled— har birining taqdiri{ status, value }yoki{ status, reason }; hech qachon rad etilmaydi.Promise.race— birinchi hal bo'lgan, xato bo'lsa ham; asosiy ishi — vaqt chegarasi (taymerni tozalang).Promise.any— birinchi muvaffaqiyatli; hammasi rad etilsa —AggregateErrorva uningerrorsmassivi.- Hech bir kombinator yutqazgan ishlarni to'xtatmaydi — u faqat kutishni to'xtatadi.
Keyingi dars: Promise yordamchilari va promisify — tayyor Promise yasash, Promise'ni tashqaridan hal qilish (Promise.withResolvers), Promise.try va callback'li funksiyalarni Promise'ga o'rash.
Manbalar
- ECMAScript spetsifikatsiyasi: "Promise.all", "Promise.allSettled", "Promise.race", "Promise.any", "AggregateError" — tc39.es/ecma262
- MDN: "Promise.all()", "Promise.allSettled()", "Promise.race()", "Promise.any()", "AggregateError" — developer.mozilla.org
- web-features (Baseline):
promise-allsettled,promise-any— github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!