Global ilovalarda samarali va mustahkam asinxron dasturlash uchun JavaScript Promise kombinatorlarini (Promise.all, Promise.allSettled, Promise.race, Promise.any) o'zlashtiring.
JavaScript Promise Kombinatorlari: Global Ilovalar uchun Ilg'or Asinxron Andozalar
Asinxron dasturlash zamonaviy JavaScript'ning asosiy tamal toshidir, ayniqsa API'lar, ma'lumotlar bazalari bilan ishlaydigan yoki ko'p vaqt talab qiladigan operatsiyalarni bajaradigan veb-ilovalarni yaratishda. JavaScript Promise'lari asinxron operatsiyalarni boshqarish uchun kuchli abstraksiyani ta'minlaydi, ammo ularni mukammal o'zlashtirish uchun ilg'or andozalarni tushunish kerak. Ushbu maqolada JavaScript Promise kombinatorlari – Promise.all, Promise.allSettled, Promise.race va Promise.any – va ulardan, ayniqsa, turli tarmoq sharoitlari va ma'lumotlar manbalariga ega bo'lgan global ilovalar kontekstida samarali va mustahkam asinxron ish jarayonlarini yaratish uchun qanday foydalanish mumkinligi haqida so'z boradi.
Promise'larni Tushunish: Qisqacha Takrorlash
Kombinatorlarga sho'ng'ishdan oldin, keling, Promise'larni tezda takrorlab olaylik. Promise asinxron operatsiyaning yakuniy natijasini ifodalaydi. U uchta holatdan birida bo'lishi mumkin:
- Pending (Kutilmoqda): Boshlang'ich holat, na bajarilgan, na rad etilgan.
- Fulfilled (Bajarildi): Operatsiya muvaffaqiyatli yakunlandi, natijaviy qiymatga ega.
- Rejected (Rad etildi): Operatsiya muvaffaqiyatsiz tugadi, sababi bilan (odatda Error obyekti).
Promise'lar an'anaviy callback'larga qaraganda asinxron operatsiyalarni boshqarishning ancha toza va qulay usulini taklif qiladi. Ular kodning o'qilishini yaxshilaydi va xatolarni qayta ishlashni soddalashtiradi. Eng muhimi, ular biz o'rganadigan Promise kombinatorlari uchun asos bo'lib xizmat qiladi.
Promise Kombinatorlari: Asinxron Operatsiyalarni Boshqarish
Promise kombinatorlari Promise obyekti ustidagi statik metodlar bo'lib, ular bir nechta Promise'larni boshqarish va muvofiqlashtirish imkonini beradi. Ular murakkab asinxron ish jarayonlarini yaratish uchun kuchli vositalarni taqdim etadi. Keling, har birini batafsil ko'rib chiqamiz.
Promise.all(): Promise'larni Parallel Bajarish va Natijalarni Jamlash
Promise.all() kirish sifatida Promise'larning iteratsiyalanuvchi (odatda massiv) ro'yxatini oladi va yagona Promise qaytaradi. Bu qaytarilgan Promise kirishdagi barcha Promise'lar bajarilganda bajariladi. Agar kirishdagi Promise'lardan birortasi rad etilsa, qaytarilgan Promise darhol birinchi rad etilgan Promise'ning sababi bilan rad etiladi.
Qo'llash holati: Bir nechta API'lardan bir vaqtda ma'lumotlarni olish va birlashtirilgan natijalarni qayta ishlash kerak bo'lganda, Promise.all() ideal tanlovdir. Masalan, dunyoning turli shaharlaridagi ob-havo ma'lumotlarini ko'rsatadigan asboblar panelini yaratishni tasavvur qiling. Har bir shaharning ma'lumotlari alohida API so'rovi orqali olinishi mumkin.
async function fetchWeatherData(city) {
try {
const response = await fetch(`https://api.example.com/weather?city=${city}`); // Haqiqiy API endpoint bilan almashtiring
if (!response.ok) {
throw new Error(`${city} uchun ob-havo ma'lumotlarini olib bo'lmadi`);
}
return await response.json();
} catch (error) {
console.error(`${city} uchun ob-havo ma'lumotlarini olishda xato: ${error}`);
throw error; // Xatoni Promise.all tomonidan tutilishi uchun qayta yuborish
}
}
async function displayWeatherData() {
const cities = ['London', 'Tokyo', 'New York', 'Sydney'];
try {
const weatherDataPromises = cities.map(city => fetchWeatherData(city));
const weatherData = await Promise.all(weatherDataPromises);
weatherData.forEach((data, index) => {
console.log(`${cities[index]}dagi ob-havo:`, data);
// UI'ni ob-havo ma'lumotlari bilan yangilash
});
} catch (error) {
console.error('Barcha shaharlar uchun ob-havo ma'lumotlarini olib bo'lmadi:', error);
// Foydalanuvchiga xato xabarini ko'rsatish
}
}
displayWeatherData();
Global Ilovalar uchun Mulohazalar:
- Tarmoq kechikishi: Turli geografik joylashuvlardagi turli API'larga qilingan so'rovlar har xil kechikishlarga duch kelishi mumkin.
Promise.all()Promise'larning bajarilish tartibini kafolatlamaydi, faqat ularning barchasi bajarilishi (yoki bittasi rad etilishi)dan so'ng umumiy Promise yakunlanishini kafolatlaydi. - API so'rovlar chegarasi: Agar siz bir xil API'ga yoki umumiy so'rov chegaralariga ega bo'lgan bir nechta API'ga ko'plab so'rovlar yuborayotgan bo'lsangiz, bu chegaralardan oshib ketishingiz mumkin. So'rov chegaralarini to'g'ri boshqarish uchun so'rovlarni navbatga qo'yish yoki eksponensial kutish kabi strategiyalarni amalga oshiring.
- Xatolarni qayta ishlash: Yodda tutingki, agar biror Promise rad etilsa, butun
Promise.all()operatsiyasi muvaffaqiyatsiz tugaydi. Agar ba'zi so'rovlar muvaffaqiyatsiz bo'lsa ham qisman ma'lumotlarni ko'rsatmoqchi bo'lsangiz, bu maqbul bo'lmasligi mumkin. Bunday hollardaPromise.allSettled()dan foydalanishni o'ylab ko'ring (quyida tushuntirilgan).
Promise.allSettled(): Muvaffaqiyat va Muvaffaqiyatsizlikni Alohida Ko'rib Chiqish
Promise.allSettled() Promise.all()ga o'xshaydi, lekin muhim bir farqi bor: u barcha kirish Promise'lari bajarilishidan yoki rad etilishidan qat'i nazar, ularning barchasi yakunlanishini kutadi. Qaytarilgan Promise har doim mos keluvchi kirish Promise'ining natijasini tavsiflovchi obyektlar massivi bilan bajariladi. Har bir obyektda status xususiyati ("fulfilled" yoki "rejected") va value (agar bajarilgan bo'lsa) yoki reason (agar rad etilgan bo'lsa) xususiyati bo'ladi.
Qo'llash holati: Bir nechta asinxron operatsiyalardan natijalarni to'plashingiz kerak bo'lganda va ba'zilarining muvaffaqiyatsizligi butun operatsiyani to'xtatmasligi kerak bo'lganda, Promise.allSettled() yaxshiroq tanlovdir. Bir nechta to'lov shlyuzlari orqali to'lovlarni amalga oshiradigan tizimni tasavvur qiling. Siz barcha to'lovlarni amalga oshirishga harakat qilib, qaysilari muvaffaqiyatli va qaysilari muvaffaqiyatsiz bo'lganini qayd etishni xohlashingiz mumkin.
async function processPayment(paymentGateway, amount) {
try {
const response = await paymentGateway.process(amount); // Haqiqiy to'lov shlyuzi integratsiyasi bilan almashtiring
if (response.status === 'success') {
return { status: 'fulfilled', value: `${paymentGateway.name} orqali to'lov muvaffaqiyatli amalga oshirildi` };
} else {
throw new Error(`${paymentGateway.name} orqali to'lov amalga oshmadi: ${response.message}`);
}
} catch (error) {
return { status: 'rejected', reason: `${paymentGateway.name} orqali to'lov amalga oshmadi: ${error.message}` };
}
}
async function processMultiplePayments(paymentGateways, amount) {
const paymentPromises = paymentGateways.map(gateway => processPayment(gateway, amount));
const results = await Promise.allSettled(paymentPromises);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(result.value);
} else {
console.error(result.reason);
}
});
// Umumiy muvaffaqiyat/muvaffaqiyatsizlikni aniqlash uchun natijalarni tahlil qilish
const successfulPayments = results.filter(result => result.status === 'fulfilled').length;
const failedPayments = results.filter(result => result.status === 'rejected').length;
console.log(`Muvaffaqiyatli to'lovlar: ${successfulPayments}`);
console.log(`Muvaffaqiyatsiz to'lovlar: ${failedPayments}`);
}
// Misol uchun to'lov shlyuzlari
const paymentGateways = [
{ name: 'PayPal', process: (amount) => Promise.resolve({ status: 'success', message: 'To'lov muvaffaqiyatli' }) },
{ name: 'Stripe', process: (amount) => Promise.reject({ status: 'error', message: 'Mablag' yetarli emas' }) },
{ name: 'Worldpay', process: (amount) => Promise.resolve({ status: 'success', message: 'To'lov muvaffaqiyatli' }) },
];
processMultiplePayments(paymentGateways, 100);
Global Ilovalar uchun Mulohazalar:
- Mustahkamlik:
Promise.allSettled()barcha asinxron operatsiyalarning, hatto ba'zilari muvaffaqiyatsiz bo'lsa ham, urinib ko'rilishini ta'minlab, ilovalaringizning mustahkamligini oshiradi. Bu, ayniqsa, muvaffaqiyatsizliklar keng tarqalgan taqsimlangan tizimlarda muhimdir. - Batafsil hisobot: Natijalar massivi har bir operatsiya natijasi haqida batafsil ma'lumot beradi, bu sizga xatolarni qayd etish, muvaffaqiyatsiz operatsiyalarni qayta urinish yoki foydalanuvchilarga aniq fikr-mulohazalar berish imkonini beradi.
- Qisman muvaffaqiyat: Siz umumiy muvaffaqiyat darajasini osongina aniqlashingiz va muvaffaqiyatli va muvaffaqiyatsiz operatsiyalar soniga qarab tegishli choralarni ko'rishingiz mumkin. Masalan, asosiy shlyuz ishlamasa, muqobil to'lov usullarini taklif qilishingiz mumkin.
Promise.race(): Eng Tez Natijani Tanlash
Promise.race() ham kirish sifatida Promise'larning iteratsiyalanuvchi ro'yxatini oladi va yagona Promise qaytaradi. Biroq, Promise.all() va Promise.allSettled() dan farqli o'laroq, Promise.race() kirishdagi Promise'lardan birortasi yakunlanishi bilan (bajarilishi yoki rad etilishi bilan) yakunlanadi. Qaytarilgan Promise birinchi yakunlangan Promise'ning qiymati yoki sababi bilan bajariladi yoki rad etiladi.
Qo'llash holati: Bir nechta manbalardan eng tez javobni tanlash kerak bo'lganda, Promise.race() yaxshi tanlovdir. Tasavvur qiling, bir xil ma'lumot uchun bir nechta serverga so'rov yuborib, birinchi kelgan javobdan foydalanasiz. Bu, ayniqsa, ba'zi serverlar vaqtincha mavjud bo'lmagan yoki boshqalarga qaraganda sekinroq bo'lgan vaziyatlarda ish faoliyatini va javob berish tezligini yaxshilashi mumkin.
async function fetchDataFromServer(serverURL) {
try {
const response = await fetch(serverURL, {signal: AbortSignal.timeout(5000)}); // 5 soniyalik taymaut qo'shish
if (!response.ok) {
throw new Error(`${serverURL} dan ma'lumotlarni olib bo'lmadi`);
}
return await response.json();
} catch (error) {
console.error(`${serverURL} dan ma'lumotlarni olishda xato: ${error}`);
throw error;
}
}
async function getFastestResponse() {
const serverURLs = [
'https://server1.example.com/data', // Haqiqiy server URL'lari bilan almashtiring
'https://server2.example.com/data',
'https://server3.example.com/data',
];
try {
const dataPromises = serverURLs.map(serverURL => fetchDataFromServer(serverURL));
const fastestData = await Promise.race(dataPromises);
console.log('Eng tez olingan ma'lumot:', fastestData);
// Eng tez ma'lumotdan foydalanish
} catch (error) {
console.error('Hech qaysi serverdan ma'lumot olib bo'lmadi:', error);
// Xatoni qayta ishlash
}
}
getFastestResponse();
Global Ilovalar uchun Mulohazalar:
- Taymautlar:
Promise.race()dan foydalanganda taymautlarni amalga oshirish juda muhim, bu esa ba'zi kirish Promise'lari hech qachon yakunlanmasa, qaytarilgan Promise'ning cheksiz kutishini oldini oladi. Yuqoridagi misolda bu maqsad uchun `AbortSignal.timeout()` ishlatilgan. - Tarmoq sharoitlari: Eng tez server foydalanuvchining geografik joylashuvi va tarmoq sharoitlariga qarab o'zgarishi mumkin. Dunyo bo'ylab foydalanuvchilar uchun kontentingizni tarqatish va ish faoliyatini yaxshilash uchun Kontent Yetkazib Berish Tarmog'idan (CDN) foydalanishni o'ylab ko'ring.
- Xatolarni qayta ishlash: Agar poygada 'g'olib' bo'lgan Promise rad etilsa, butun Promise.race rad etiladi. Kutilmagan rad etishlarning oldini olish uchun har bir Promise'da tegishli xatolarni qayta ishlash mavjudligiga ishonch hosil qiling. Shuningdek, agar "g'olib" promise taymaut tufayli rad etilsa (yuqorida ko'rsatilganidek), boshqa promise'lar fonda bajarilishda davom etadi. Agar ular endi kerak bo'lmasa, `AbortController` yordamida ushbu boshqa promise'larni bekor qilish uchun mantiq qo'shishingiz kerak bo'lishi mumkin.
Promise.any(): Birinchi Bajarilishni Qabul Qilish
Promise.any() Promise.race() ga o'xshaydi, lekin biroz boshqacha xususiyatga ega. U birinchi kirish Promise'i bajarilishini kutadi. Agar barcha kirish Promise'lari rad etilsa, Promise.any() rad etish sabablari massivini o'z ichiga olgan AggregateError bilan rad etiladi.
Qo'llash holati: Bir nechta manbalardan ma'lumot olish kerak bo'lganda va siz faqat birinchi muvaffaqiyatli natija bilan qiziqsangiz, Promise.any() yaxshi tanlovdir. Bu sizda bir xil ma'lumotni taqdim etadigan zaxira ma'lumot manbalari yoki muqobil API'lar mavjud bo'lganda foydalidir. U tezlikdan ko'ra muvaffaqiyatga ustunlik beradi, chunki u ba'zi Promise'lar tezda rad etilsa ham, birinchi bajarilishni kutadi.
async function fetchDataFromSource(sourceURL) {
try {
const response = await fetch(sourceURL);
if (!response.ok) {
throw new Error(`${sourceURL} dan ma'lumotlarni olib bo'lmadi`);
}
return await response.json();
} catch (error) {
console.error(`${sourceURL} dan ma'lumotlarni olishda xato: ${error}`);
throw error;
}
}
async function getFirstSuccessfulData() {
const dataSources = [
'https://source1.example.com/data', // Haqiqiy ma'lumot manbai URL'lari bilan almashtiring
'https://source2.example.com/data',
'https://source3.example.com/data',
];
try {
const dataPromises = dataSources.map(sourceURL => fetchDataFromSource(sourceURL));
const data = await Promise.any(dataPromises);
console.log('Birinchi muvaffaqiyatli olingan ma'lumot:', data);
// Muvaffaqiyatli ma'lumotdan foydalanish
} catch (error) {
if (error instanceof AggregateError) {
console.error('Hech qaysi manbadan ma'lumot olib bo'lmadi:', error.errors);
// Xatoni qayta ishlash
} else {
console.error('Kutilmagan xato yuz berdi:', error);
}
}
}
getFirstSuccessfulData();
Global Ilovalar uchun Mulohazalar:
- Zaxira manbalar:
Promise.any()o'xshash ma'lumotlarni taqdim etadigan zaxira ma'lumot manbalari bilan ishlashda ayniqsa foydalidir. Agar bir manba mavjud bo'lmasa yoki sekin ishlasa, siz ma'lumotlarni taqdim etish uchun boshqalariga tayanasiz. - Xatolarni qayta ishlash: Barcha kirish Promise'lari rad etilganda yuboriladigan
AggregateErrorni qayta ishlashga ishonch hosil qiling. Bu xato alohida rad etish sabablari massivini o'z ichiga oladi, bu sizga muammolarni tuzatish va tashxislash imkonini beradi. - Ustuvorlik: Promise'larni
Promise.any()ga qaysi tartibda berishingiz muhim. Muvaffaqiyatli natija ehtimolini oshirish uchun eng ishonchli yoki eng tez ma'lumot manbalarini birinchi o'ringa qo'ying.
To'g'ri Kombinatorni Tanlash: Xulosa
Ehtiyojlaringizga mos Promise kombinatorini tanlashga yordam beradigan qisqacha xulosa:
- Promise.all(): Barcha Promise'lar muvaffaqiyatli bajarilishi kerak bo'lganda va har qanday Promise rad etilsa, darhol ishni to'xtatish kerak bo'lganda foydalaning.
- Promise.allSettled(): Barcha Promise'lar muvaffaqiyat yoki muvaffaqiyatsizlikdan qat'i nazar yakunlanishini kutish kerak bo'lganda va har bir natija haqida batafsil ma'lumot kerak bo'lganda foydalaning.
- Promise.race(): Bir nechta Promise'lardan eng tez natijani tanlash kerak bo'lganda va faqat birinchi yakunlangan natija muhim bo'lganda foydalaning.
- Promise.any(): Bir nechta Promise'lardan birinchi muvaffaqiyatli natijani qabul qilish kerak bo'lganda va ba'zi Promise'lar rad etilishi muhim bo'lmaganda foydalaning.
Ilg'or Andozalar va Eng Yaxshi Amaliyotlar
Promise kombinatorlarining asosiy qo'llanilishidan tashqari, yodda tutish kerak bo'lgan bir nechta ilg'or andozalar va eng yaxshi amaliyotlar mavjud:
Parallel Bajarishni Cheklash
Ko'p sonli Promise'lar bilan ishlaganda, ularni bir vaqtning o'zida parallel ravishda bajarish tizimingizni ortiqcha yuklashi yoki API so'rov chegaralaridan oshib ketishi mumkin. Siz parallel bajarishni quyidagi usullar yordamida cheklashingiz mumkin:
- Bo'laklarga bo'lish (Chunking): Promise'larni kichikroq bo'laklarga bo'lib, har bir bo'lakni ketma-ket qayta ishlang.
- Semafor ishlatish: Bir vaqtda bajariladigan operatsiyalar sonini nazorat qilish uchun semaforni amalga oshiring.
Bu yerda bo'laklarga bo'lish usulidan foydalanishga misol:
async function processInChunks(promises, chunkSize) {
const results = [];
for (let i = 0; i < promises.length; i += chunkSize) {
const chunk = promises.slice(i, i + chunkSize);
const chunkResults = await Promise.all(chunk);
results.push(...chunkResults);
}
return results;
}
// Qo'llash misoli
const myPromises = [...Array(100)].map((_, i) => Promise.resolve(i)); // 100 ta promise yaratish
processInChunks(myPromises, 10) // Bir vaqtning o'zida 10 ta promise'ni qayta ishlash
.then(results => console.log('Barcha promise'lar bajarildi:', results));
Xatolarni To'g'ri Qayta Ishlash
Promise'lar bilan ishlashda xatolarni to'g'ri qayta ishlash juda muhimdir. Asinxron operatsiyalar paytida yuzaga kelishi mumkin bo'lgan xatolarni ushlash uchun try...catch bloklaridan foydalaning. Muvaffaqiyatsiz operatsiyalarni avtomatik ravishda qayta urinish uchun p-retry yoki retry kabi kutubxonalardan foydalanishni o'ylab ko'ring.
async function fetchDataWithRetry(url, retries = 3) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (retries > 0) {
console.log(`1 soniyadan so'ng qayta urinilmoqda... (Qolgan urinishlar: ${retries})`);
await new Promise(resolve => setTimeout(resolve, 1000)); // 1 soniya kutish
return fetchDataWithRetry(url, retries - 1);
} else {
console.error('Maksimal urinishlarga erishildi. Operatsiya muvaffaqiyatsiz tugadi.');
throw error;
}
}
}
Async/Await'dan Foydalanish
async va await Promise'lar bilan ishlashning sinxron ko'rinishdagi usulini taqdim etadi. Ular kodning o'qilishi va saqlanishini sezilarli darajada yaxshilashi mumkin.
Potensial xatolarni qayta ishlash uchun await ifodalari atrofida try...catch bloklaridan foydalanishni unutmang.
Bekor Qilish
Ba'zi stsenariylarda, ayniqsa uzoq davom etadigan operatsiyalar yoki foydalanuvchi tomonidan boshlangan harakatlar bilan ishlashda kutilayotgan Promise'larni bekor qilishingiz kerak bo'lishi mumkin. Promise bekor qilinishi kerakligini bildirish uchun AbortController API'sidan foydalanishingiz mumkin.
const controller = new AbortController();
const signal = controller.signal;
async function fetchDataWithCancellation(url) {
try {
const response = await fetch(url, { signal });
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('So'rov bekor qilindi');
} else {
console.error('Ma'lumotlarni olishda xato:', error);
}
throw error;
}
}
fetchDataWithCancellation('https://api.example.com/data')
.then(data => console.log('Ma'lumotlar olindi:', data))
.catch(error => console.error('So'rov muvaffaqiyatsiz tugadi:', error));
// So'rov operatsiyasini 5 soniyadan keyin bekor qilish
setTimeout(() => {
controller.abort();
}, 5000);
Xulosa
JavaScript Promise kombinatorlari mustahkam va samarali asinxron ilovalarni yaratish uchun kuchli vositalardir. Promise.all, Promise.allSettled, Promise.race va Promise.any ning nozikliklarini tushunib, siz murakkab asinxron ish jarayonlarini boshqarishingiz, xatolarni to'g'ri qayta ishlashingiz va ish faoliyatini optimallashtirishingiz mumkin. Global ilovalarni ishlab chiqishda tarmoq kechikishi, API so'rov chegaralari va ma'lumotlar manbalarining ishonchliligi kabi omillarni hisobga olish juda muhimdir. Ushbu maqolada muhokama qilingan andozalar va eng yaxshi amaliyotlarni qo'llash orqali siz ham samarali, ham bardoshli JavaScript ilovalarini yaratib, butun dunyo bo'ylab foydalanuvchilarga yuqori darajadagi tajriba taqdim etishingiz mumkin.