Async/Await — xatolarni ushlash, parallel va ketma-ket bajarish
Muammodan boshlaylik
Async/Await ni o'rgandik. Lekin amalda ikki savol doimo chiqadi.
Birinchi savol: Bir funksiyada bir nechta await bor. Har biriga alohida try/catch yozishim kerakmi? Yoki bitta yetarliMi?
Ikkinchi savol: Uchta await ketma-ket yozilgan. Lekin ular bir-biriga bog'liq emas — birining natijasi ikkinchisiga kerak emas. Nima farq qiladi?
Bu ikki savolga aniq javob bilmasdan — async kod yo sekin ishlaydi, yo xatolar noto'g'ri boshqariladi.
Ketma-ket va parallel — farq nima?
Ikkita vazifa bor: foydalanuvchi ma'lumotini olish (1 soniya) va mahsulotlar ro'yxatini olish (1 soniya).
Ketma-ket — biri tugamaguncha keyingisi boshlanmaydi
async function yukla() {
const foydalanuvchi = await getUser(); // ← 1 soniya kutiladi
const mahsulotlar = await getMahsulot(); // ← yana 1 soniya kutiladi
render(foydalanuvchi, mahsulotlar);
}
// Jami: 2 soniya
Parallel — bir vaqtda ikkalasi boshlanadi
async function yukla() {
const [foydalanuvchi, mahsulotlar] = await Promise.all([
getUser(),
getMahsulot(),
]);
render(foydalanuvchi, mahsulotlar);
}
// Jami: 1 soniya (ikkalasi bir vaqtda ishladi)
Hayotiy o'xshatma
Ertalab nonushta tayyorlamoqdasiz. Choy damlash kerak — 3 daqiqa. Tuxum qovurish kerak — 3 daqiqa.
Ketma-ket: avval choy, keyin tuxum — 6 daqiqa. Parallel: choyni qo'yib, tuxumni ham boshlash — 3 daqiqa.
Agar biri ikkinchisining natijasiga bog'liq bo'lmasa — parallel qilish kerak.
Qachon ketma-ket, qachon parallel?
Ketma-ket — keyingi qadam oldingi natijaga bog'liq bo'lganda:
async function buyurtmaYarat(userId, mahsulotId) {
const user = await getUser(userId);
// user.faolmi tekshiriladi — user kerak
if (!user.faol) throw new Error("Foydalanuvchi faol emas");
const mahsulot = await getMahsulot(mahsulotId);
// mahsulot.ombori tekshiriladi — mahsulot kerak
if (mahsulot.ombor === 0) throw new Error("Omborda yo'q");
const buyurtma = await yaratBuyurtma(user.id, mahsulot.id);
// buyurtma yaratildi — ikkalasi ham kerak edi
return buyurtma;
}
Bu yerda ketma-ket to'g'ri — har qadam oldingi natijaga bog'liq.
Parallel — bir-biriga bog'liq bo'lmaganda:
// ❌ Ketma-ket yozilgan, lekin bog'liq emas — sekin
async function sahifahYukla(userId) {
const user = await getUser(userId);
const postlar = await getPostlar(userId); // ← user ga bog'liq emas!
const notiflar = await getNotiflar(userId); // ← user ga bog'liq emas!
render(user, postlar, notiflar);
}
// Jami: 300ms + 200ms + 400ms = 900ms
// ✅ Parallel — 2x tez
async function sahifahYukla(userId) {
const [user, postlar, notiflar] = await Promise.all([
getUser(userId),
getPostlar(userId),
getNotiflar(userId),
]);
render(user, postlar, notiflar);
}
// Jami: max(300, 200, 400) = 400ms
Qoida oddiy: "bu so'rovning natijasi boshqa so'rovga kerakmi?" — kerak bo'lsa ketma-ket, kerak bo'lmasa parallel.
Xatolarni ushlash — qanday qilish kerak?
Bitta try/catch — oddiy holat
Ko'p hollarda bitta try/catch yetarli:
async function yukla(id) {
try {
const user = await getUser(id);
const postlar = await getPostlar(user.id);
render(user, postlar);
} catch (xato) {
// Ikkala so'rovdan ham xato shu yerga tushadi
xatoBoshqar(xato);
}
}
Bitta try/catch — istalgan qatordagi xatoni ushlaydi. Bu — eng oddiy va ko'p ishlatiladigan usul.
Alohida try/catch — har xil xatolarni boshqarish
Ba'zan har bir so'rovning xatosi har xil tarzda hal qilinishi kerak:
async function yukla(id) {
let user;
try {
user = await getUser(id);
} catch (xato) {
// Foydalanuvchi topilmasa — boshqa sahifaga o'tkazish
window.location = "/login";
return;
}
let postlar;
try {
postlar = await getPostlar(user.id);
} catch (xato) {
// Postlar yuklanmasa — bo'sh ro'yxat ko'rsatish, davom etish
postlar = [];
}
render(user, postlar);
}
.catch() bilan standart qiymat berish
Eng ixcham usul — har bir await yoniga .catch() qo'shish:
async function yukla(id) {
const user = await getUser(id).catch(() => null);
const postlar = await getPostlar(id).catch(() => []);
if (!user) {
showError("Foydalanuvchi topilmadi");
return;
}
render(user, postlar); // postlar bo'sh bo'lsa ham ishlaydi
}
Loop da parallel so'rovlar
Massiv elementlari uchun parallel so'rovlar — Promise.all va map birga:
const idlar = [1, 2, 3, 4, 5];
// ❌ Ketma-ket — jami: 1+1+1+1+1 = 5 soniya
for (const id of idlar) {
const user = await getUser(id); // biri tugamaguncha keyingisi boshlanmaydi
console.log(user);
}
// ✅ Parallel — jami: ~1 soniya (hammasi bir vaqtda)
const users = await Promise.all(idlar.map(id => getUser(id)));
console.log(users);
forEach bilan async — nega ishlamaydi?
forEach — callback bilan chaqiradi, lekin u qaytargan Promise ni kutmaydi. Bu oddiy JavaScript ning dizayn qarori: forEach asinxron bo'lganda nima qilishni bilmaydi.
// ❌ forEach — natija tartibsiz, "tugadi" darhol chiqadi
[1, 2, 3].forEach(async (id) => {
const user = await getUser(id);
console.log(user);
});
console.log("tugadi"); // ← loop hali tugamagan!
// ✅ for...of — tartibli, kutadi
for (const id of [1, 2, 3]) {
const user = await getUser(id);
console.log(user);
}
console.log("tugadi"); // ← haqiqatan oxirida
Tez-tez uchraydigan xatolar
Parallel bo'lishi mumkin so'rovlarni ketma-ket yozish:
Bu eng ko'p uchraydigan xato — kod to'g'ri ishlaydi, lekin keraksiz sekin.
// ❌ — bog'liq emas, lekin ketma-ket
const a = await getSomething();
const b = await getSomethingElse(); // a ga bog'liq emas, lekin a tugaguncha kutadi
// ✅
const [a, b] = await Promise.all([getSomething(), getSomethingElse()]);
Promise.all da xatoni ko'rmaslik:
// ❌ — biri xato bersa hammasi yo'qoladi, catch yo'q
const [a, b] = await Promise.all([getA(), getB()]);
// ✅
const [a, b] = await Promise.all([
getA().catch(() => null),
getB().catch(() => null),
]);
Xulosa
Ketma-ket — await birin-ketin. Har qadam oldingi natijaga bog'liq bo'lganda.
Parallel — await Promise.all([...]). Bir-biriga bog'liq bo'lmagan so'rovlar — doima parallel. Sekin kodning eng keng tarqalgan sababi — parallel bo'lishi mumkin narsani ketma-ket yozish.
Xato ushlash — bitta try/catch oddiy holat uchun. Har xil xatolar uchun — alohida try/catch yoki .catch() bilan standart qiymat.
forEach + async — ishlamaydi. for...of yoki Promise.all([].map(...)) ishlatiladi.
Keyingi dars
41-dars: Fetch API — HTTP so'rovlar, headers, method, body