JavaScript'da parallel qayta ishlash qudratini oching. Tezroq va mustahkamroq ilovalar uchun Promise.all, allSettled, race va any yordamida konkurent Promise'larni boshqarishni o'rganing.
JavaScript Konkurentligini O'zlashtirish: Parallel Promise'larni Qayta Ishlashga Chuqur Kirish
Zamonaviy veb-dasturlash landshaftida samaradorlik bu xususiyat emas; bu asosiy talabdir. Dunyo bo'ylab foydalanuvchilar ilovalarning tez, sezgir va uzluksiz bo'lishini kutishadi. Ushbu samaradorlik muammosining markazida, ayniqsa JavaScript'da, asinxron operatsiyalarni samarali boshqarish tushunchasi yotadi. API'dan ma'lumotlarni olishdan faylni o'qishgacha yoki ma'lumotlar bazasiga so'rov yuborishgacha, ko'plab vazifalar bir zumda bajarilmaydi. Ushbu kutish davrlarini qanday boshqarishimiz sust ishlaydigan ilova va yoqimli silliq foydalanuvchi tajribasi o'rtasidagi farqni yaratishi mumkin.
JavaScript o'z tabiatiga ko'ra bir oqimli tildir. Bu shuni anglatadiki, u bir vaqtning o'zida faqat bitta kod qismini bajara oladi. Bu cheklovdek tuyulishi mumkin, ammo JavaScript'ning hodisalar tsikli va bloklanmaydigan I/O modeli unga asinxron vazifalarni aql bovar qilmaydigan samaradorlik bilan bajarishga imkon beradi. Ushbu modelning zamonaviy asosini Promise tashkil etadi — bu asinxron operatsiyaning yakuniy bajarilishini (yoki muvaffaqiyatsizligini) ifodalovchi ob'ekt.
Biroq, shunchaki Promise'lar yoki ularning nafis `async/await` sintaksisidan foydalanish avtomatik ravishda optimal samaradorlikni kafolatlamaydi. Dasturchilar uchun keng tarqalgan xato bu bir nechta mustaqil asinxron vazifalarni ketma-ket bajarish bo'lib, bu keraksiz to'siqlarni yaratadi. Aynan shu yerda konkurent promise'larni qayta ishlash yordamga keladi. Bir nechta asinxron operatsiyalarni parallel ravishda ishga tushirib va ularni birgalikda kutish orqali, biz umumiy bajarilish vaqtini keskin kamaytirishimiz va ancha samaraliroq ilovalar yaratishimiz mumkin.
Ushbu keng qamrovli qo'llanma sizni JavaScript konkurentligi dunyosiga chuqur olib kiradi. Biz tilning o'ziga o'rnatilgan vositalarni — `Promise.all()`, `Promise.allSettled()`, `Promise.race()` va `Promise.any()` ni o'rganamiz, bu sizga parallel vazifalarni professional kabi boshqarishga yordam beradi. Siz asinxronlikni endi o'rganayotgan yosh dasturchi bo'lasizmi yoki o'z patternlaringizni takomillashtirishni istagan tajribali muhandis bo'lasizmi, ushbu maqola sizni tezroq, chidamliroq va murakkabroq JavaScript kodini yozish uchun bilim bilan ta'minlaydi.
Birinchi, Tezkor Aniqlashtirish: Konkurentlik va Parallelizm
Davom etishdan oldin, ko'pincha bir-birining o'rnida ishlatiladigan, ammo kompyuter fanlarida alohida ma'nolarga ega bo'lgan ikkita atamani aniqlashtirish muhimdir: konkurentlik va parallelizm.
- Konkurentlik bu bir vaqt oralig'ida bir nechta vazifalarni boshqarish tushunchasidir. Bu bir vaqtning o'zida ko'p narsalar bilan shug'ullanish haqida. Agar tizim bittadan ortiq vazifani avvalgisi tugashini kutmasdan boshlay olsa, ishga tushira olsa va yakunlay olsa, u konkurent hisoblanadi. JavaScript'ning bir oqimli muhitida konkurentlik hodisalar tsikli orqali amalga oshiriladi, bu esa dvigatelga vazifalar o'rtasida almashinish imkonini beradi. Bitta uzoq davom etadigan vazifa (masalan, tarmoq so'rovi) kutayotgan paytda, dvigatel boshqa ishlarni bajarishi mumkin.
- Parallelizm bu bir vaqtning o'zida bir nechta vazifalarni bajarish tushunchasidir. Bu bir vaqtning o'zida ko'p ishlarni qilish haqida. Haqiqiy parallelizm ko'p yadroli protsessorni talab qiladi, bu yerda turli oqimlar turli yadrolarda bir vaqtning o'zida ishlashi mumkin. Veb-vorkerlar brauzerga asoslangan JavaScript'da haqiqiy parallelizmga imkon bersa-da, biz muhokama qilayotgan asosiy konkurentlik modeli yagona asosiy oqimga tegishlidir.
I/O bilan bog'liq operatsiyalar (tarmoq so'rovlari kabi) uchun JavaScript'ning konkurent modeli parallelizm *effektini* beradi. Biz bir vaqtning o'zida bir nechta so'rovlarni boshlashimiz mumkin. JavaScript dvigateli javoblarni kutayotganda, u boshqa ishlarni bajarish uchun erkin bo'ladi. Operatsiyalar tashqi resurslar (serverlar, fayl tizimlari) nuqtai nazaridan 'parallel' ravishda sodir bo'lmoqda. Bu biz foydalanadigan kuchli modeldir.
Ketma-ketlik Qopqog'i: Keng Tarqalgan Anti-Pattern
Keling, keng tarqalgan xatoni aniqlashdan boshlaylik. Dasturchilar `async/await` ni birinchi marta o'rganganlarida, sintaksis shunchalik toza ko'rinadiki, sinxron ko'rinadigan, ammo bilmagan holda ketma-ket va samarasiz bo'lgan kod yozish oson. Tasavvur qiling, boshqaruv panelini yaratish uchun foydalanuvchining profilini, uning so'nggi postlarini va bildirishnomalarini olishingiz kerak.
Sodda yondashuv quyidagicha ko'rinishi mumkin:
Misol: Samarasiz Ketma-ket Yuklash
async function fetchDashboardDataSequentially(userId) {
console.time('sequentialFetch');
console.log('Foydalanuvchi profilini yuklash...');
const userProfile = await fetchUserProfile(userId); // Shu yerda kutadi
console.log('Foydalanuvchi postlarini yuklash...');
const userPosts = await fetchUserPosts(userId); // Shu yerda kutadi
console.log('Foydalanuvchi bildirishnomalarini yuklash...');
const userNotifications = await fetchUserNotifications(userId); // Shu yerda kutadi
console.timeEnd('sequentialFetch');
return { userProfile, userPosts, userNotifications };
}
// Tasavvur qiling, bu funksiyalarning bajarilishi uchun vaqt kerak
// fetchUserProfile -> 500ms
// fetchUserPosts -> 800ms
// fetchUserNotifications -> 1000ms
Bu yerda nima noto'g'ri? Har bir `await` kalit so'zi promise bajarilguncha `fetchDashboardDataSequentially` funksiyasining bajarilishini to'xtatib turadi. `userPosts` uchun so'rov `userProfile` so'rovi to'liq tugamaguncha hatto boshlanmaydi. `userNotifications` uchun so'rov `userPosts` qaytib kelmaguncha boshlanmaydi. Bu uchta tarmoq so'rovi bir-biriga bog'liq emas; kutish uchun hech qanday sabab yo'q! Umumiy sarflangan vaqt barcha alohida vaqtlar yig'indisi bo'ladi:
Umumiy Vaqt ≈ 500ms + 800ms + 1000ms = 2300ms
Bu samaradorlik uchun katta to'siq. Biz bundan ancha yaxshiroq qila olamiz.
Samaradorlikni Ochish: Konkurent Bajarilishning Kuchi
Yechim - barcha asinxron operatsiyalarni bir vaqtda, ularni darhol kutmasdan boshlashdir. Bu ularga konkurent ravishda ishlashga imkon beradi. Biz kutilayotgan Promise ob'ektlarini o'zgaruvchilarda saqlashimiz va keyin ularning barchasi tugashini kutish uchun Promise kombinatori dan foydalanishimiz mumkin.
Misol: Samarali Konkurent Yuklash
async function fetchDashboardDataConcurrently(userId) {
console.time('concurrentFetch');
console.log('Barcha yuklashlarni bir vaqtda boshlash...');
const profilePromise = fetchUserProfile(userId);
const postsPromise = fetchUserPosts(userId);
const notificationsPromise = fetchUserNotifications(userId);
// Endi ularning barchasi tugashini kutamiz
const [userProfile, userPosts, userNotifications] = await Promise.all([
profilePromise,
postsPromise,
notificationsPromise
]);
console.timeEnd('concurrentFetch');
return { userProfile, userPosts, userNotifications };
}
Bu versiyada biz uchta yuklash funksiyasini `await` siz chaqiramiz. Bu darhol barcha uchta tarmoq so'rovini boshlaydi. JavaScript dvigateli ularni asosiy muhitga (brauzer yoki Node.js) topshiradi va uchta kutilayotgan Promise'ni qaytarib oladi. Keyin, `Promise.all()` bu uchta promise'ning barchasi bajarilishini kutish uchun ishlatiladi. Umumiy sarflangan vaqt endi yig'indi bilan emas, balki eng uzoq davom etadigan operatsiya bilan belgilanadi.
Umumiy Vaqt ≈ max(500ms, 800ms, 1000ms) = 1000ms
Biz ma'lumotlarni yuklash vaqtini yarmidan ko'proqqa qisqartirdik! Bu parallel promise'larni qayta ishlashning asosiy printsipidir. Endi keling, JavaScript'ning ushbu konkurent vazifalarni boshqarish uchun taqdim etadigan kuchli vositalarini o'rganamiz.
Promise Kombinatorlar To'plami: `all`, `allSettled`, `race` va `any`
JavaScript `Promise` ob'ektida to'rtta statik metodni taqdim etadi, ular promise kombinatorlari deb nomlanadi. Ularning har biri promise'lar iterable'ini (massiv kabi) qabul qiladi va yangi yagona promise qaytaradi. Bu yangi promise'ning xatti-harakati siz qaysi kombinatorni ishlatishingizga bog'liq.
1. `Promise.all()`: Hammasi yoki Hech Narsa Yondashuvi
`Promise.all()` keyingi qadam uchun barchasi muhim bo'lgan bir guruh vazifalaringiz bo'lganda mukammal vositadir. U mantiqiy "VA" shartini ifodalaydi: 1-vazifa VA 2-vazifa VA 3-vazifa barchasi muvaffaqiyatli bo'lishi kerak.
- Kirish: Promise'lar iterable'i.
- Xatti-harakat: U kiruvchi promise'larning barchasi bajarilganda (fulfilled) bajariladigan yagona promise qaytaradi. Bajarilgan qiymat, kiruvchi promise'lar natijalaridan iborat, xuddi shu tartibdagi massivdir.
- Muvaffaqiyatsizlik Rejimi: U kiruvchi promise'lardan birortasi rad etilishi (reject) bilanoq darhol rad etiladi. Rad etish sababi birinchi rad etilgan promise'ning sababidir. Bu ko'pincha "tezkor muvaffaqiyatsizlik" (fail-fast) xatti-harakati deb ataladi.
Qo'llash Holati: Muhim Ma'lumotlarni Agregatsiyalash
Bizning boshqaruv paneli misolimiz mukammal qo'llash holatidir. Agar siz foydalanuvchining profilini yuklay olmasangiz, uning postlari va bildirishnomalarini ko'rsatish mantiqsiz bo'lishi mumkin. Butun komponent barcha uchta ma'lumot nuqtasining mavjudligiga bog'liq.
// API so'rovlarini simulyatsiya qilish uchun yordamchi
const mockApiCall = (value, delay, shouldFail = false) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject(new Error(`API so'rovi muvaffaqiyatsiz bo'ldi: ${value}`));
} else {
console.log(`Bajarildi: ${value}`);
resolve({ data: value });
}
}, delay);
});
};
async function loadCriticalData() {
console.log('Muhim ma\'lumotlar uchun Promise.all ishlatilmoqda...');
try {
const [profile, settings, permissions] = await Promise.all([
mockApiCall('userProfile', 400),
mockApiCall('userSettings', 700),
mockApiCall('userPermissions', 500)
]);
console.log('Barcha muhim ma\'lumotlar muvaffaqiyatli yuklandi!');
// Endi UI'ni profil, sozlamalar va ruxsatlar bilan render qiling
} catch (error) {
console.error('Muhim ma\'lumotlarni yuklashda xatolik:', error.message);
// Foydalanuvchiga xato xabarini ko'rsating
}
}
// Agar bittasi muvaffaqiyatsiz bo'lsa nima bo'ladi?
async function loadCriticalDataWithFailure() {
console.log('\nPromise.all muvaffaqiyatsizligini namoyish etish...');
try {
const results = await Promise.all([
mockApiCall('userProfile', 400),
mockApiCall('userSettings', 700, true), // Bu muvaffaqiyatsiz bo'ladi
mockApiCall('userPermissions', 500)
]);
} catch (error) {
console.error('Promise.all rad etildi:', error.message);
// Eslatma: 'userProfile' va 'userPermissions' so'rovlari tugallangan bo'lishi mumkin,
// ammo butun operatsiya muvaffaqiyatsiz bo'lgani uchun ularning natijalari yo'qoladi.
}
}
loadCriticalData();
// Bir oz kechikishdan so'ng, muvaffaqiyatsizlik misolini chaqiring
setTimeout(loadCriticalDataWithFailure, 2000);
`Promise.all()` ning Kamchiligi
Asosiy kamchilik uning tezkor muvaffaqiyatsizlik tabiatidir. Agar siz sahifadagi o'nta turli, mustaqil vidjetlar uchun ma'lumotlarni yuklayotgan bo'lsangiz va bitta API ishlamay qolsa, `Promise.all()` rad etiladi va siz boshqa to'qqizta muvaffaqiyatli so'rov natijalarini yo'qotasiz. Aynan shu yerda bizning keyingi kombinatorimiz o'zini ko'rsatadi.
2. `Promise.allSettled()`: Chidamli Yig'uvchi
ES2020 da taqdim etilgan `Promise.allSettled()` chidamlilik uchun o'yinni o'zgartiruvchi bo'ldi. U har bir promise'ning natijasini, u muvaffaqiyatli bo'ladimi yoki muvaffaqiyatsiz bo'ladimi, bilishni istaganingizda mo'ljallangan. U hech qachon rad etmaydi.
- Kirish: Promise'lar iterable'i.
- Xatti-harakat: U har doim bajariladigan yagona promise qaytaradi. U kiruvchi promise'larning barchasi yakunlanganda (bajarilgan yoki rad etilgan) bajariladi. Bajarilgan qiymat har bir promise'ning natijasini tavsiflovchi ob'ektlar massividir.
- Natija Formati: Har bir natija ob'ektida `status` xususiyati mavjud.
- Agar bajarilgan bo'lsa: `{ status: 'fulfilled', value: theResult }`
- Agar rad etilgan bo'lsa: `{ status: 'rejected', reason: theError }`
Qo'llash Holati: Muhim Bo'lmagan, Mustaqil Operatsiyalar
Bir nechta mustaqil komponentlarni ko'rsatadigan sahifani tasavvur qiling: ob-havo vidjeti, yangiliklar lentasi va birja ticker'i. Agar yangiliklar lentasi API'si ishlamay qolsa, siz hali ham ob-havo va birja ma'lumotlarini ko'rsatishni xohlaysiz. `Promise.allSettled()` bu uchun mukammaldir.
async function loadDashboardWidgets() {
console.log('\nMustaqil vidjetlar uchun Promise.allSettled ishlatilmoqda...');
const results = await Promise.allSettled([
mockApiCall('Ob-havo ma\'lumotlari', 600),
mockApiCall('Yangiliklar lentasi', 1200, true), // Bu API ishlamayapti
mockApiCall('Birja ticker\'i', 800)
]);
console.log('Barcha promise\'lar yakunlandi. Natijalarni qayta ishlash...');
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`${index}-vidjet muvaffaqiyatli yuklandi, ma'lumotlar:`, result.value.data);
// Bu vidjetni UI'ga render qiling
} else {
console.error(`${index}-vidjetni yuklashda xatolik:`, result.reason.message);
// Bu vidjet uchun maxsus xatolik holatini ko'rsating
}
});
}
loadDashboardWidgets();
`Promise.allSettled()` bilan ilovangiz ancha mustahkamroq bo'ladi. Bitta muvaffaqiyatsizlik nuqtasi butun foydalanuvchi interfeysini ishdan chiqaradigan kaskadli muammolarga olib kelmaydi. Siz har bir natijani chiroyli tarzda hal qila olasiz.
3. `Promise.race()`: Finish Chizig'iga Birinchi Yetib Kelgan
`Promise.race()` o'z nomiga mos ishni bajaradi. U bir guruh promise'larni bir-biriga qarshi qo'yadi va birinchisi finish chizig'ini kesib o'tishi bilanoq g'olibni e'lon qiladi, uning muvaffaqiyatli yoki muvaffaqiyatsiz bo'lishidan qat'i nazar.
- Kirish: Promise'lar iterable'i.
- Xatti-harakat: U kiruvchi promise'lardan birinchisi yakunlanishi bilanoq yakunlanadigan (bajariladi yoki rad etiladi) yagona promise qaytaradi. Qaytarilgan promise'ning bajarilgan qiymati yoki rad etish sababi "g'olib" promise'niki bilan bir xil bo'ladi.
- Muhim Eslatma: Boshqa promise'lar bekor qilinmaydi. Ular fonda ishlashni davom ettiradi va ularning natijalari shunchaki `Promise.race()` konteksti tomonidan e'tiborsiz qoldiriladi.
Qo'llash Holati: Taymautni Amalga Oshirish
`Promise.race()` uchun eng keng tarqalgan va amaliy qo'llash holati - bu asinxron operatsiyaga taymautni majburlash. Siz o'zingizning asosiy operatsiyangizni `setTimeout` promise'i bilan "poygaga" qo'yishingiz mumkin. Agar operatsiyangiz juda uzoq davom etsa, taymaut promise'i birinchi bo'lib yakunlanadi va siz buni xato sifatida hal qilishingiz mumkin.
function createTimeout(delay) {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`Operatsiya ${delay}ms dan keyin vaqt tugashi bilan to'xtatildi`));
}, delay);
});
}
async function fetchDataWithTimeout() {
console.log('\nTaymaut uchun Promise.race ishlatilmoqda...');
try {
const result = await Promise.race([
mockApiCall('ba\'zi muhim ma\'lumotlar', 2000), // Bu juda ko'p vaqt oladi
createTimeout(1500) // Bu poygada g'olib chiqadi
]);
console.log('Ma\'lumotlar muvaffaqiyatli olindi:', result.data);
} catch (error) {
console.error(error.message);
}
}
fetchDataWithTimeout();
Yana Bir Qo'llash Holati: Zaxira Endpiontlar
Siz shuningdek, bir xil resurs uchun bir nechta zaxira serverlarga so'rov yuborish va qaysi server eng tezkor bo'lsa, o'shaning javobini olish uchun `Promise.race()` dan foydalanishingiz mumkin. Biroq, bu xavfli, chunki agar eng tez server xato qaytarsa (masalan, 500 status kodi), `Promise.race()` darhol rad etadi, hatto biroz sekinroq server muvaffaqiyatli javob qaytargan bo'lsa ham. Bu bizni bu stsenariy uchun yanada mosroq bo'lgan oxirgi kombinatorimizga olib keladi.
4. `Promise.any()`: Birinchi Muvaffaqiyatli Bo'lgan
ES2021 da taqdim etilgan `Promise.any()` `Promise.race()` ning yanada optimistik versiyasiga o'xshaydi. U ham birinchi promise'ning yakunlanishini kutadi, lekin u aynan birinchi bajarilganini qidiradi.
- Kirish: Promise'lar iterable'i.
- Xatti-harakat: U kiruvchi promise'lardan birortasi bajarilishi bilanoq bajariladigan yagona promise qaytaradi. Bajarilgan qiymat birinchi bajarilgan promise'ning qiymatidir.
- Muvaffaqiyatsizlik Rejimi: U faqatgina barcha kiruvchi promise'lar rad etilsagina rad etadi. Rad etish sababi maxsus `AggregateError` ob'ektidir, uning `errors` xususiyati mavjud — bu barcha alohida rad etish sabablarining massividir.
Qo'llash Holati: Zaxira Manbalardan Yuklash
Bu resursni bir nechta manbalardan, masalan, asosiy va zaxira serverlar yoki bir nechta Kontent Yetkazib Berish Tarmoqlari (CDN) dan olish uchun mukammal vositadir. Siz faqat iloji boricha tezroq bitta muvaffaqiyatli javob olishga qiziqasiz.
async function fetchResourceFromMirrors() {
console.log('\nEng tez muvaffaqiyatli manbani topish uchun Promise.any ishlatilmoqda...');
try {
const resource = await Promise.any([
mockApiCall('Asosiy CDN', 800, true), // Tezda muvaffaqiyatsiz bo'ladi
mockApiCall('Yevropa manbasi', 1200), // Sekinroq, lekin muvaffaqiyatli bo'ladi
mockApiCall('Osiyo manbasi', 1100) // Shuningdek, muvaffaqiyatli, lekin Yevropa manbasidan sekinroq
]);
console.log('Resurs manbadan muvaffaqiyatli olindi:', resource.data);
} catch (error) {
if (error instanceof AggregateError) {
console.error('Barcha manbalar resursni taqdim eta olmadi.');
// Siz alohida xatoliklarni tekshirishingiz mumkin:
error.errors.forEach(err => console.log('- ' + err.message));
}
}
}
fetchResourceFromMirrors();
Ushbu misolda, `Promise.any()` Asosiy CDN'ning tezkor muvaffaqiyatsizligini e'tiborsiz qoldiradi va Yevropa manbasining bajarilishini kutadi, shu nuqtada u o'sha ma'lumotlar bilan hal qilinadi va Osiyo manbasining natijasini samarali ravishda e'tiborsiz qoldiradi.
Ish Uchun To'g'ri Vosatani Tanlash: Qisqa Qo'llanma
To'rtta kuchli variant bilan, qaysi birini ishlatishni qanday hal qilasiz? Mana oddiy qaror qabul qilish tizimi:
- Menga BARCHA promise'larning natijalari kerakmi va ulardan BIRORTASI muvaffaqiyatsiz bo'lsa, bu falokatmi?
Promise.all()dan foydalaning. Bu bir-biriga chambarchas bog'liq, hammasi-yoki-hech-narsa stsenariylari uchun. - Menga BARCHA promise'larning natijasini, ular muvaffaqiyatli yoki muvaffaqiyatsiz bo'lishidan qat'i nazar, bilishim kerakmi?
Promise.allSettled()dan foydalaning. Bu har bir natijani qayta ishlashni va ilovaning chidamliligini saqlashni istagan bir nechta mustaqil vazifalarni boshqarish uchun. - Menga faqat eng birinchi tugagan promise qiziqmi, u muvaffaqiyatli yoki muvaffaqiyatsiz bo'lishidan qat'i nazar?
Promise.race()dan foydalaning. Bu asosan taymautlarni yoki birinchi natija (har qanday turdagi) yagona ahamiyatga ega bo'lgan boshqa poyga sharoitlarini amalga oshirish uchun. - Menga faqat birinchi MUVAFAQQIYATLI bo'lgan promise qiziqmi va muvaffaqiyatsiz bo'lganlarini e'tiborsiz qoldirsam bo'ladimi?
Promise.any()dan foydalaning. Bu zaxiralash bilan bog'liq stsenariylar uchun, masalan, bir xil resurs uchun bir nechta endpoint'larni sinab ko'rish.
Ilg'or Patternlar va Real Hayotdagi Holatlar
Promise kombinatorlari nihoyatda kuchli bo'lsa-da, professional dasturlash ko'pincha biroz ko'proq noziklikni talab qiladi.
Konkurentlikni Cheklash va Throttling
Agar sizda 1000 ta ID'dan iborat massiv bo'lsa va har biri uchun ma'lumotlarni olishni istasangiz nima bo'ladi? Agar siz barcha 1000 ta promise hosil qiluvchi chaqiruvni `Promise.all()` ga shunchaki o'tkazsangiz, siz bir zumda 1000 ta tarmoq so'rovini yuborasiz. Bu bir nechta salbiy oqibatlarga olib kelishi mumkin:
- Serverning Haddan Tashqari Yuklanishi: Siz so'rov yuborayotgan serverni haddan tashqari yuklashingiz mumkin, bu esa xatoliklarga yoki barcha foydalanuvchilar uchun samaradorlikning pasayishiga olib keladi.
- So'rovlar Cheklovi (Rate Limiting): Ko'pgina ommaviy API'larda so'rovlar chegarasi mavjud. Siz, ehtimol, o'z chegarangizga yetib, `429 Too Many Requests` xatolarini olasiz.
- Kliyent Resurslari: Kliyent (brauzer yoki server) bir vaqtning o'zida shuncha ochiq tarmoq ulanishlarini boshqarishda qiynalishi mumkin.
Yechim - promise'larni partiyalarga bo'lib qayta ishlash orqali konkurentlikni cheklashdir. Buni o'zingiz yozishingiz mumkin bo'lsa-da, `p-limit` yoki `async-pool` kabi yetuk kutubxonalar buni osonlik bilan hal qiladi. Mana buni qo'lda qanday amalga oshirish mumkinligining kontseptual misoli:
async function processInBatches(items, batchSize, processingFn) {
let results = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
console.log(`${i}-indeksdan boshlanadigan partiyani qayta ishlash...`);
const batchPromises = batch.map(processingFn);
const batchResults = await Promise.allSettled(batchPromises);
results = results.concat(batchResults);
}
return results;
}
// Foydalanish misoli:
const userIds = Array.from({ length: 20 }, (_, i) => i + 1);
// Biz 20 ta foydalanuvchini 5 tadan qilib partiyalarga bo'lib qayta ishlaymiz
processInBatches(userIds, 5, id => mockApiCall(`user_${id}`, Math.random() * 1000))
.then(allResults => {
console.log('\nPartiyalarni qayta ishlash tugallandi.');
const successful = allResults.filter(r => r.status === 'fulfilled').length;
const failed = allResults.filter(r => r.status === 'rejected').length;
console.log(`Jami Natijalar: ${allResults.length}, Muvaffaqiyatli: ${successful}, Muvaffaqiyatsiz: ${failed}`);
});
Bekor Qilish Haqida Eslatma
Native Promise'lar bilan uzoq vaqtdan beri mavjud bo'lgan muammo shundaki, ularni bekor qilib bo'lmaydi. Bir marta promise yaratganingizdan so'ng, u tugagunicha ishlaydi. `Promise.race` sekin natijani e'tiborsiz qoldirishga yordam berishi mumkin bo'lsa-da, asosiy operatsiya resurslarni iste'mol qilishda davom etadi. Tarmoq so'rovlari uchun zamonaviy yechim bu `AbortController` API bo'lib, u sizga `fetch` so'roviga uni bekor qilish kerakligi haqida signal berishga imkon beradi. `AbortController` ni promise kombinatorlari bilan integratsiya qilish uzoq davom etadigan konkurent vazifalarni mustahkam boshqarish va tozalash usulini taqdim etishi mumkin.
Xulosa: Ketma-ket Fikrlashdan Konkurent Fikrlashga
Asinxron JavaScript'ni o'zlashtirish bu bir sayohatdir. U bir oqimli hodisalar tsiklini tushunishdan boshlanadi, aniqlik uchun Promise'lar va `async/await` dan foydalanishga o'tadi va samaradorlikni maksimal darajada oshirish uchun konkurent fikrlash bilan yakunlanadi. Ketma-ket `await` fikrlash tarzidan parallel yondashuvga o'tish dasturchining ilova sezgirligini oshirish uchun qila oladigan eng ta'sirli o'zgarishlardan biridir.
O'rnatilgan promise kombinatorlaridan foydalangan holda, siz turli xil real hayotiy stsenariylarni nafislik va aniqlik bilan hal qilishga tayyorsiz:
- Muhim, hammasi-yoki-hech-narsa ma'lumotlar bog'liqliklari uchun `Promise.all()` dan foydalaning.
- Mustaqil komponentlarga ega chidamli UI'larni yaratish uchun `Promise.allSettled()` ga tayaning.
- Vaqt cheklovlarini qo'llash va cheksiz kutishlarning oldini olish uchun `Promise.race()` ni ishlating.
- Zaxira ma'lumot manbalari bilan tez va xatolarga chidamli tizimlar yaratish uchun `Promise.any()` ni tanlang.
Keyingi safar ketma-ket bir nechta `await` ifodalarini yozayotganingizda, to'xtab, so'rang: "Bu operatsiyalar haqiqatan ham bir-biriga bog'liqmi?" Agar javob yo'q bo'lsa, sizda kodingizni konkurentlik uchun qayta ishlash uchun ajoyib imkoniyat bor. Promise'laringizni birgalikda boshlang, o'z mantig'ingiz uchun to'g'ri kombinatorni tanlang va ilovangiz samaradorligi qanday oshishini kuzating.