JavaScript Promise Advanced Patterns

Chuqurlashtirilgan qo'llanma. Promise zanjirlari, xatolarni boshqarish, Promise.all, Promise.race va boshqa ilg'or usullar

So'nggi yangilanish: 2024-12-31

Bugun biz JavaScript Promise-larining ilg'or usullari va naqshlari haqida chuqur o'rganamiz. Bu mavzu asinxron dasturlashni yanada samarali va kuchli qilish uchun juda muhimdir.

Promise Zanjirlari (Promise Chaining)

Promise zanjirlari - bu bir nechta asinxron operatsiyalarni ketma-ket bajarish usuli. Bu usul Promise-larni bir-biriga bog'lash orqali amalga oshiriladi.

function getUser(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ id: userId, name: 'John Doe' });
    }, 1000);
  });
}

function getUserPosts(user) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve([
        { id: 1, title: "John's first post" },
        { id: 2, title: "John's second post" }
      ]);
    }, 1000);
  });
}

getUser(1)
  .then(user => {
    console.log('User:', user);
    return getUserPosts(user);
  })
  .then(posts => {
    console.log('Posts:', posts);
  })
  .catch(error => {
    console.error('Error:', error);
  });

Bu misolda, biz avval foydalanuvchini olamiz, keyin esa shu foydalanuvchining postlarini olamiz. Har bir .then() metodi yangi Promise qaytaradi, bu esa zanjirni davom ettirish imkonini beradi.

Xatolarni Boshqarish (Error Handling)

Promise-larda xatolarni boshqarish .catch() metodi orqali amalga oshiriladi. Bu metod zanjirning istalgan joyida sodir bo'lgan xatolarni ushlaydi.

function riskyOperation() {
  return new Promise((resolve, reject) => {
    if (Math.random() > 0.5) {
      resolve('Operation successful');
    } else {
      reject(new Error('Operation failed'));
    }
  });
}

riskyOperation()
  .then(result => {
    console.log(result);
    return riskyOperation();
  })
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Caught an error:', error.message);
  })
  .finally(() => {
    console.log('Operation finished');
  });

Bu misolda, .catch() metodi har qanday xatoni ushlaydi, .finally() esa operatsiya muvaffaqiyatli bo'lishi yoki xato berishi-berilmasligidan qat'i nazar bajariladi.

Promise.all()

Promise.all() metodi bir nechta Promise-larni parallel ravishda bajarish va ularning natijalarini kutish uchun ishlatiladi.

const promise1 = new Promise(resolve => setTimeout(() => resolve('one'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('two'), 2000));
const promise3 = new Promise(resolve => setTimeout(() => resolve('three'), 3000));

Promise.all([promise1, promise2, promise3])
  .then(values => {
    console.log(values); // ['one', 'two', 'three']
  })
  .catch(error => {
    console.error('Error in promises:', error);
  });

Promise.all() barcha Promise-lar muvaffaqiyatli bajarilgandan so'ng natijalarni massiv ko'rinishida qaytaradi. Agar birorta Promise rad etilsa (reject), Promise.all() darhol xato qaytaradi.

Promise.race()

Promise.race() metodi berilgan Promise-lardan eng birinchi bajarilganining (muvaffaqiyatli yoki muvaffaqiyatsiz) natijasini qaytaradi.

const promise1 = new Promise(resolve => setTimeout(() => resolve('quick'), 800));
const promise2 = new Promise(resolve => setTimeout(() => resolve('slow'), 1500));

Promise.race([promise1, promise2])
  .then(result => {
    console.log('Fastest promise resolved:', result); // 'quick'
  })
  .catch(error => {
    console.error('Error in race:', error);
  });

Bu usul, masalan, vaqt chegarasi qo'yish uchun foydali bo'lishi mumkin.

Promise.allSettled()

Promise.allSettled() barcha Promise-lar bajarilishini (muvaffaqiyatli yoki muvaffaqiyatsiz) kutadi va har birining holatini qaytaradi.

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 200, 'bar'));

Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
    results.forEach((result) => console.log(result.status));
  });
// Output: "fulfilled", "rejected", "fulfilled"

Bu metod barcha Promise-larning natijalarini bilish kerak bo'lganda foydalidir, hatto ba'zilari rad etilgan bo'lsa ham.

Asinxron Funktsiyalar bilan Ishlash (Working with Async Functions)

Asinxron funktsiyalar Promise-lar bilan ishlashni yanada soddalashtirib beradi.

async function fetchUserAndPosts(userId) {
  try {
    const user = await getUser(userId);
    console.log('User:', user);
    
    const posts = await getUserPosts(user);
    console.log('Posts:', posts);
    
    return { user, posts };
  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

fetchUserAndPosts(1)
  .then(result => console.log('Final result:', result))
  .catch(error => console.error('Caught error:', error));

async/await sintaksisi Promise zanjirlarini yanada o'qilishi oson ko'rinishda yozish imkonini beradi.

Amaliy Misol: Ma'lumotlar Bazasidan Ma'lumot Olish

Keling, Promise-larning ilg'or usullarini amalda qo'llab ko'ramiz. Tasavvur qiling, biz onlayn do'konning ma'lumotlar bazasidan ma'lumotlarni olishimiz kerak.

// Ma'lumotlar bazasi simulyatsiyasi
const db = {
  getUser: (id) => new Promise(resolve => setTimeout(() => resolve({ id, name: `User ${id}` }), 200)),
  getOrders: (userId) => new Promise(resolve => setTimeout(() => resolve([
    { id: 1, userId, product: 'Kitob' },
    { id: 2, userId, product: 'Qalam' }
  ]), 300)),
  getProduct: (name) => new Promise(resolve => setTimeout(() => resolve({ name, price: Math.floor(Math.random() * 100) }), 100))
};

async function getUserInfo(userId) {
  try {
    const user = await db.getUser(userId);
    const orders = await db.getOrders(userId);
    
    const productPromises = orders.map(order => db.getProduct(order.product));
    const products = await Promise.all(productPromises);
    
    const orderDetails = orders.map((order, index) => ({
      ...order,
      productDetails: products[index]
    }));

    return {
      user,
      orders: orderDetails
    };
  } catch (error) {
    console.error('Error fetching user info:', error);
    throw error;
  }
}

getUserInfo(1)
  .then(result => console.log('User info:', JSON.stringify(result, null, 2)))
  .catch(error => console.error('Error:', error));

Bu misolda biz:

  1. Foydalanuvchi ma'lumotlarini olamiz
  2. Foydalanuvchining buyurtmalarini olamiz
  3. Har bir buyurtma uchun mahsulot ma'lumotlarini parallel ravishda olamiz (Promise.all() yordamida)
  4. Barcha ma'lumotlarni birlashtirib, yakuniy natijani qaytaramiz

Tez-tez So'raladigan Savollar (TSS)

  1. S: Promise zanjirida xatoni qanday ushlash mumkin? J: Zanjirning oxirida .catch() metodini qo'shish orqali barcha xatolarni ushlash mumkin. Shuningdek, har bir .then() ichida xatolarni alohida ushlash uchun try-catch blokidan foydalanish mumkin.
  2. S: Promise.all() va Promise.allSettled() o'rtasidagi farq nima? J: Promise.all() barcha Promise-lar muvaffaqiyatli bajarilishini kutadi va birorta xato yuz bersa, darhol to'xtaydi. Promise.allSettled() esa barcha Promise-lar (muvaffaqiyatli yoki muvaffaqiyatsiz) bajarilishini kutadi va har birining holatini qaytaradi.
  3. S: async/await Promise-lardan nimasi bilan farq qiladi? J: async/await - bu Promise-lar bilan ishlashning yanada o'qilishi oson sintaksisidir. U Promise-larni ishlatadi, lekin kodning ko'rinishini sinxron kodga o'xshatib beradi.
  4. S: Promise-larni bekor qilish mumkinmi? J: Promise-larni to'g'ridan-to'g'ri bekor qilish imkoni yo'q. Lekin AbortController yoki o'zingiz yaratgan bekor qilish mexanizmidan foydalanish mumkin.
  5. S: Promise.race() va Promise.any() o'rtasidagi farq nima? J: Promise.race() birinchi bajarilgan Promise natijasini qaytaradi (muvaffaqiyatli yoki muvaffaqiyatsiz). Promise.any() esa faqat birinchi muvaffaqiyatli bajarilgan Promise natijasini qaytaradi.
  6. S: Promise-larda xotira sizib chiqishi (memory leak) xavfi bormi? J: Ha, agar Promise-lar to'g'ri ishlatilmasa (masalan, uzun vaqt hal qilinmagan Promise-lar), xotira sizib chiqishi mumkin. Har doim .catch() metodini qo'shish va zarur bo'lmagan Promise-larni tozalash muhimdir.
  7. S: Promise-lar bilan ishlashda eng ko'p uchraydigan xatolar qanday? J: Eng ko'p uchraydigan xatolar: .catch() metodini unutish, Promise zanjirlarini noto'g'ri tuzish, va asinxron kodni sinxron kod kabi yozishga urinish.
  8. S: Promise-lar va callback-lar o'rtasida qanday farq bor? J: Promise-lar callback-larga nisbatan ko'proq imkoniyatlar beradi: ular zanjirlanishi mumkin, xatolarni boshqarish osonroq, va "callback hell" muammosini hal qiladi.
  9. S: Promise-larni debug qilishning eng yaxshi usuli qanday? J: console.log() yordamida har bir bosqichni kuzatish, xatolarni .catch() metodida ushlash, va brauzerning DevTools-idagi "Async" stacktrace-lardan foydalanish.
  10. S: Promise-lar bilan ishlashda qanday yaxshi amaliyotlarga amal qilish kerak? J: Har doim .catch() metodini qo'shish, Promise zanjirlarini aniq va tushunarli qilib tuzish, murakkab mantiq uchun async/awaitdan foydalanish, va parallel bajarilishi mumkin bo'lgan operatsiyalar uchun Promise.all()ni ishlatish.

Xulosa

Promise-larning ilg'or usullari JavaScript-da murakkab asinxron operatsiyalarni boshqarish uchun kuchli vositalardir. Ular yordamida siz kod yozishni yanada samarali va tushunarli qila olasiz. Promise zanjirlari, xatolarni boshqarish, Promise.all(), Promise.race() va async/await kabi usullar sizga turli xil vaziyatlarda moslashuvchan yechimlar yaratish imkonini beradi.

Promise-lar bilan ishlashda, doimo xatolarni to'g'ri boshqarish, kodning o'qilishi va samaradorligini hisobga olish muhimdir. Asinxron dasturlashning bu usullarini o'zlashtirib, siz murakkab JavaScript ilovalarini yaratishda yanada malakali bo'lasiz.

Esda tuting, yaxshi asinxron kod - bu nafaqat ishlayotgan, balki boshqalar (shu jumladan kelajakdagi o'zingiz) uchun ham tushunarli va xizmat ko'rsatish oson bo'lgan kod. Promise-larning ilg'or usullarini to'g'ri qo'llash orqali, siz bu maqsadga erishishingiz mumkin.

Qo'shimcha manbalar

  1. JavaScript.info - Promises, async/await
  2. MDN Web Docs - Using Promises
  3. Exploring Async/Await Functions in JavaScript

Agar sizda yana savollar bo'lsa yoki biror mavzu bo'yicha qo'shimcha tushuntirish kerak bo'lsa, bemalol so'rang. JavaScript-da Promise-larning ilg'or usullarini o'zlashtirish va qo'llash bo'yicha bilimlaringizni oshirishda omad tilayman!

Promise-lar va asinxron dasturlash JavaScript-ning muhim qismidir. Ularni to'g'ri ishlatish orqali, siz yanada samarali va kengaytiriladigan dasturlar yaratishingiz mumkin. Esda tuting, amaliyot - mukammallikning kalitidir. Shuning uchun turli loyihalarda Promise-larni qo'llab ko'ring va o'z tajribangizni oshiring.

Agar siz Promise-lar va asinxron dasturlash haqida yanada chuqurroq o'rganmoqchi bo'lsangiz, quyidagi mavzularni o'rganishni tavsiya qilaman:

  1. Promise-larning ichki ishlash mexanizmi
  2. Asinxron iteratorlar va generatorlar
  3. RxJS kabi reaktiv dasturlash kutubxonalari
  4. Node.js-da asinxron dasturlash
  5. Web Worker-lar va asinxron JavaScript