IlmHamroh
JavaScript Full-stack/11-qism. Asinxron JavaScript va tarmoq7/32-dars21 daqiqa
Mundarija (34)

JavaScript async / await: asinxron kodni sinxron kabi yozish

Qisqacha: async funksiya doim Promise qaytaradi: return qiymati — bajarilish, throw — rad etish. Uning ichida await promise funksiyani Promise hal bo'lguncha to'xtatadi va natijani qaytaradi: const stol = await stolTop(4);. Dastur esa to'xtamaydi — funksiyadan keyingi kod davom etadi. Rad etilgan await — oddiy throw kabi, uni try/catch ushlaydi.

Bu darsda

  • async funksiya nima qaytarishini va await qayerda, qanday to'xtashini tushuntira olasiz.
  • Promise zanjirini async/await bilan tekis, sinxron ko'rinishdagi kodga aylantira olasiz.
  • Asinxron xatolarni tanish try/catch/finally bilan ushlay olasiz.
  • "Suzib yurgan" (floating) Promise xatosini tanib, tuzata olasiz.
  • await bor kodning chiqish tartibini event loop bo'yicha oldindan ayta olasiz.

Oldin bilishingiz kerak: Promise zanjiri, Promise asoslari, try / catch / finally.

1. Nega bu kerak?

Promise zanjiri piramidani tekisladi. Lekin uch joyda zanjir hamon noqulay.

Oldingi natijalar. Chekda ham stol raqami, ham buyurtma bo'lishi kerak. Tekis zanjirda stol faqat birinchi then da ko'rinadi — uni pastga yetkazish uchun obyektlar yig'ish yoki ichma-ich then kerak bo'ldi.

Shart va sikllar. "Stol topilmasa — ayvondan qidir", "uch marta qayta urin" — zanjirda bularni yozish uchun rekursiya kerak bo'ldi (qaytaUrin). Oddiy if va for ishlamaydi.

Xatolar. try / catch / finally darsida try asinxron xatoni ushlamasligini ko'rdik va "Promise'dagi xatolar uchun boshqa yo'l bor — 11-qismda" degan edik. Zanjirda o'sha "boshqa yo'l" — catch metodi. Lekin u tanish try/catch dan boshqacha yoziladi.

Asl orzu esa oddiy: asinxron kodni ham sinxron kod kabi — yuqoridan pastga, o'zgaruvchilar, if, for va try/catch bilan yozish. async/await aynan shuni beradi. U ES2017 da qo'shilgan va bugun asinxron kodning asosiy shakli.

Muhimi: async/await — yangi mexanizm emas. U Promise'ning ustiga qurilgan sintaksis. Ichida hamon o'sha Promise'lar, o'sha then va o'sha microtask navbati. Shuning uchun oldingi ikki dars bekor ketmaydi — ularsiz await xatolarini topib bo'lmaydi.

2. async funksiya

2.1 Doim Promise qaytaradi

Funksiya oldiga async kalit so'zini qo'ysangiz, u asinxron funksiya bo'ladi. Birinchi farq — u har doim Promise qaytaradi:

js
async function narxniOl() {
  return 35000;
}

const natija = narxniOl();
console.log(natija);
console.log(natija instanceof Promise);
natija.then((narx) => console.log("then:", narx));

Konsolda:

text
Promise { 35000 }
true
then: 35000

Biz 35000 ni qaytardik, lekin chaqiruvchi Promise oldi — shu qiymat bilan bajarilgan. Uni then bilan o'qiymiz, xuddi oldingi darslardagidek. (instanceof — obyekt shu klassning nusxasimi: Object.create va instanceof.)

throw esa rad etilgan Promise'ga aylanadi:

js
async function stolTop(odam) {
  if (odam > 20) {
    throw new Error("Bunday katta stol yo'q");
  }
  return 5;
}

stolTop(25)
  .then((stol) => console.log("Stol:", stol))
  .catch((xato) => console.log("Xato:", xato.message));
console.log("Funksiya chaqirildi, dastur davom etmoqda");

Konsolda:

text
Funksiya chaqirildi, dastur davom etmoqda
Xato: Bunday katta stol yo'q

throw dastur to'xtatmadi va chaqiruv joyida ham xato chiqarmadi. U Promise'ning rad etilishiga aylandi va catch ga keldi. Bu Promise zanjiri dagi qoidaning aynan o'zi: async funksiya — xuddi then callback'i kabi — natijasini Promise'ga o'raydi.

async funksiya ichida Chaqiruvchi oladi
return qiymat shu qiymat bilan bajarilgan Promise
hech narsa qaytarmaydi undefined bilan bajarilgan Promise
return promise o'sha Promise kabi hal bo'ladigan Promise
throw xato shu xato bilan rad etilgan Promise

2.2 async qayerga yoziladi

async har qanday funksiya shakliga qo'yiladi:

js
async function bronQil(stol) { ... }           // e'lon
const bronQil = async function (stol) { ... }; // ifoda
const bronQil = async (stol) => { ... };       // arrow
const kassa = {
  async tolovQil(summa) { ... },               // obyekt metodi
};
class Oshxona {
  async tayyorla(taom) { ... }                 // klass metodi
}

Arrow funksiyada async qavslardan oldin turadi: async (stol) => .... Bitta parametrli qisqa shakl ham bor: async stol => ....

Tekshirib ko'ring: async function f() {} — f() nima qaytaradi?

Javob

undefined bilan bajarilgan Promise — Promise { undefined }. Funksiya hech narsa qaytarmadi, lekin async bo'lgani uchun natija baribir Promise'ga o'raldi.

3. await

3.1 Natijani kutib olish

await — faqat async funksiya ichida ishlatiladigan operator. await promise — "shu Promise hal bo'lguncha funksiyani to'xtat; bajarilsa — uning qiymatini ber".

Promise zanjiri dagi to'rt qadamli bronni qayta yozamiz:

js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
async function stolTop(odam) {
  await kut(100);
  if (odam > 20) throw new Error("Bunday katta stol yo'q");
  return 5;
}
async function bronQil(stol) {
  await kut(100);
  return `${stol}-stol, 19:00`;
}
async function chekYoz(buyurtma) {
  await kut(100);
  return `${buyurtma}: 35000 so'm`;
}

async function bronJarayoni(odam) {
  const stol = await stolTop(odam);
  const bron = await bronQil(stol);
  const chek = await chekYoz(`${bron}, osh`);
  console.log("Chek:", chek);
  console.log("Stol raqami alohida:", stol);
}

bronJarayoni(4);

Konsolda:

text
Chek: 5-stol, 19:00, osh: 35000 so'm
Stol raqami alohida: 5

bronJarayoni ga qarang: then yo'q, callback yo'q. Har qator oldingisi tugagach bajariladi — xuddi sinxron kod kabi. Natijalar oddiy const o'zgaruvchilarda. Oxirgi qatorda stol hamon ko'rinadi — zanjirdagi "oldingi natija" muammosi o'z-o'zidan yo'qoldi.

Bu ko'rinish aldamasin: kod sinxron ko'rinadi, lekin sinxron emas. Har await da bronJarayoni to'xtaydi va stekni bo'shatadi. Uch qadam orasida 300 ms o'tadi — shu vaqt ichida boshqa kod, bosishlar va taymerlar bemalol ishlaydi. Sinxron "kutish" (Sinxron va asinxron kod dagi bo'sh sikl) esa sahifani qotirardi.

Yordamchi funksiyalar ham async bo'ldi: kut(100) ni kutib, keyin natija qaytaradi. kut esa oddiy funksiya — u Promise'ni new Promise bilan yasaydi. Taymer kabi callback'li API'ni Promise'ga aylantirishda new Promise hamon kerak — async buni qila olmaydi.

3.2 await funksiyani to'xtatadi, dasturni emas

Eng muhim tushuncha. await da faqat shu funksiya to'xtaydi. Funksiyani chaqirgan kod esa davom etadi. Ishga tushirishdan oldin tartibni o'zingiz ayting:

js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
async function oshDamla() {
  console.log("2. Qozon yondi");
  await kut(300);
  console.log("4. Osh tayyor");
}
console.log("1. Buyurtma");
oshDamla();
console.log("3. Choy quyildi");

Konsolda:

text
1. Buyurtma
2. Qozon yondi
3. Choy quyildi
4. Osh tayyor

Kodda "4" "3" dan yuqorida yozilgan, lekin keyin chiqdi. Qadamma-qadam kuzating — ayniqsa oshDamla stekdan qachon chiqib, qachon qaytishiga:

Uch qoida:

  • async funksiya birinchi await gacha sinxron ishlaydi — "2" darhol chiqdi. Bu executor'ning darhol ishlashiga o'xshaydi (Promise asoslari).
  • await da funksiya stekdan chiqadi. Stek bo'shaydi, boshqa kod ishlaydi — bloklash yo'q.
  • Promise hal bo'lgach, funksiyaning davomi microtask sifatida qaytadi — xuddi then callback'i kabi.

Aslida await dan keyingi hamma qatorlar — yashirin then callback'i. oshDamla ni shunday tasavvur qilsangiz bo'ladi: console.log("2..."); return kut(300).then(() => console.log("4..."));. Til buni siz uchun yozadi.

3.3 Promise bo'lmagan qiymatni await qilish

await 35000 ham ishlaydi — qiymat darhol bajarilgan Promise'ga o'raladi. Lekin funksiya baribir to'xtaydi va davomi microtask'da keladi:

js
async function narx() {
  console.log("2. funksiya ichida");
  const n = await 35000;
  console.log("4. await'dan keyin:", n);
}

console.log("1");
narx();
console.log("3");

Konsolda:

text
1
2. funksiya ichida
3
4. await'dan keyin: 35000

Kutadigan narsa yo'q edi, lekin "4" baribir "3" dan keyin chiqdi. await — doim "to'xta va microtask'da davom et". Bu ham Promise'ning "doim asinxron" kafolati: await dan keyingi kod hech qachon chaqiruvchidan oldin ishlamaydi.

Tekshirib ko'ring: oshDamla da await kut(300) o'rniga kut(300) (await'siz) yozilsa, tartib qanday bo'ladi?

Javob

1, 2, 4, 3. await bo'lmasa, funksiya to'xtamaydi: taymer qo'yiladi, lekin "4. Osh tayyor" darhol, sinxron chiqadi. Keyin funksiya tugaydi va skript "3" ni chiqaradi. Osh "tayyor" bo'ldi, qozon esa hali qaynayapti — bu xato.

3.4 Generator bilan aloqasi

Generatorlar chuqur darsida ijroEt ijrochisini yozgan edik: generator yield bilan "narx kerak" deydi va to'xtaydi, ijrochi javobni topib, next(javob) bilan uni davom ettiradi. O'shanda "async/await shu g'oyani tilning o'ziga olib kirdi" degan edik. Endi solishtiring:

Generator + ijrochi async funksiya
function* async function
const osh = yield topshiriq; const osh = await promise;
ijrochi next(javob) bilan davom ettiradi dvigatel Promise bajarilganda davom ettiradi
ijrochini o'zingiz yozasiz ijrochi tilning ichida

await — "Promise'ni yield qil, bajarilganda meni next(natija) bilan uyg'ot" degani. Funksiyaning o'zgaruvchilari va qaysi qatorda to'xtagani generatordagidek saqlanib qoladi. 2017 gacha dasturchilar aynan shu naqshni kutubxona bilan (co) ishlatgan.

4. Xatolar: try / catch / finally

4.1 Rad etilgan await — throw

await qilingan Promise rad etilsa, await turgan qatorda xato tashlanadi — xuddi u yerda throw yozilgandek. Demak uni oddiy try/catch ushlaydi:

js
function narxniSora(taom) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (taom === "osh") resolve(35000);
      else reject(new Error(`Menyuda yo'q: ${taom}`));
    }, 100);
  });
}

async function narxniKorsat(taom) {
  console.log("Yuklanmoqda...");
  try {
    const narx = await narxniSora(taom);
    console.log(`${taom}: ${narx} so'm`);
  } catch (xato) {
    console.log("Xato:", xato.message);
  } finally {
    console.log("Yuklanish belgisi yashirildi");
  }
}

narxniKorsat("palov");

Konsolda:

text
Yuklanmoqda...
Xato: Menyuda yo'q: palov
Yuklanish belgisi yashirildi

try / catch / finally darsidagi va'da bajarildi. O'shanda try taymer ichidagi xatoni ushlamagan edi: try taymerni qo'yib, tugab bo'lgan edi. Bu yerda esa await funksiyani try blokining ichida to'xtatadi. Xato kelganda funksiya hamon try ichida — shuning uchun catch uni ushlaydi.

try ichidagi await dan keyingi qator (console.log(...narx...)) bajarilmadi — sinxron throw dagi kabi. finally esa ikkala holatda ham ishlaydi: "osh" bilan sinab ko'ring.

4.2 Bitta try — bir nechta await

Bitta try ichida bir nechta await bo'lsa, ulardan istalganining xatosi bitta catch ga keladi. Bu zanjir oxiridagi bitta .catch() ning aynan o'zi:

js
async function bronJarayoni(odam) {
  try {
    const stol = await stolTop(odam);
    const bron = await bronQil(stol);
    return await chekYoz(bron);
  } catch (xato) {
    console.log("Bron bo'lmadi:", xato.message);
    return null;
  }
}

Agar har qadam uchun alohida munosabat kerak bo'lsa (masalan stol topilmasa — ayvondan qidirish), shu qadamni alohida try ga o'rang. Endi bu oddiy if/try bilan yoziladi — zanjirdagi kabi rekursiya shart emas.

Tekshirib ko'ring: bronJarayoni(25) chaqirildi (stolTop 20 dan ko'pga xato beradi). bronQil chaqiriladimi va funksiya nima qaytaradi?

Javob

Yo'q. Birinchi await qatorida xato tashlanadi, try ning qolgan qatorlari o'tkazib yuboriladi. catch "Bron bo'lmadi: ..." deb yozadi va null qaytaradi — demak bronJarayoni(25) null bilan bajarilgan Promise qaytaradi, rad etilgan emas.

4.3 return va return await farqi

Oxirgi kodda return await chekYoz(bron) yozdik. Shunchaki return chekYoz(bron) bo'lsa-chi? try dan tashqarida farqi yo'q. try ichida esa bor:

js
async function serverdanOl() {
  throw new Error("Server javob bermadi");
}

async function birinchi() {
  try {
    return serverdanOl();
  } catch {
    return "zaxira narx";
  }
}

async function ikkinchi() {
  try {
    return await serverdanOl();
  } catch {
    return "zaxira narx";
  }
}

ikkinchi().then((x) => console.log("ikkinchi:", x));
birinchi()
  .then((x) => console.log("birinchi:", x))
  .catch((xato) => console.log("birinchi xato:", xato.message));

Konsolda:

text
ikkinchi: zaxira narx
birinchi xato: Server javob bermadi

Nega shunday? try faqat tashlangan (throw) xatoni ushlaydi. birinchi da return rad etilgan Promise'ni ochmasdan, "qutisi bilan" chaqiruvchiga uzatdi. Hech narsa tashlanmadi — catch ishlamadi, xato tashqaridagi .catch ga ketdi. ikkinchi da esa await Promise'ni try ichida ochdi. Rad etilgan Promise await da throw ga aylandi va catch uni ushladi. Qoida: try ichida Promise qaytarsangiz — return await yozing.

catch dan keyin (xato) yo'qligiga e'tibor bering: xato obyekti kerak bo'lmasa, uni tashlab ketish mumkin (try / catch / finally).

Tekshirib ko'ring: narxniKorsat("osh") chaqirilsa, konsolda qaysi uch qator chiqadi?

Javob

Yuklanmoqda..., osh: 35000 so'm, Yuklanish belgisi yashirildi. Promise bajarildi, await qiymatni berdi, try oxirigacha ishladi, catch o'tkazib yuborildi, finally baribir ishladi.

5. "Suzib yurgan" Promise

5.1 await ni unutish

async funksiyani await siz chaqirsangiz, u ishlaydi, lekin uning natijasi va xatosi hech kimga kerak bo'lmay qoladi. Bunday Promise suzib yurgan (floating) Promise deyiladi — u "hech kimga bog'lanmagan":

js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
async function saqla() {
  await kut(100);
  throw new Error("Disk to'la");
}

async function tugmaBosildi() {
  try {
    saqla();
    console.log("Saqlandi!");
  } catch (xato) {
    console.log("Saqlanmadi:", xato.message);
  }
}

tugmaBosildi();

Node 24 da (fayl yo'li qisqartirildi):

text
Saqlandi!
file:///C:/.../11/suzuvchi.mjs:6
  throw new Error("Disk to'la");
        ^

Error: Disk to'la
    at saqla (file:///C:/.../11/suzuvchi.mjs:6:9)

Node.js v24.21.0

Ikki yomon narsa birdaniga. Birinchisi, foydalanuvchi "Saqlandi!" ni ko'rdi — saqlash hali boshlanmagan bo'lsa ham. Ikkinchisi, try/catch xatoni ushlamadi va dastur to'xtadi. Sabab bitta: await yo'q. Funksiya saqla() dan Promise oldi, unga qaramadi va try dan chiqib ketdi. Xato 100 ms dan keyin, hech kim kutmagan Promise'da chiqdi — ushlanmagan rad etilish.

Tuzatish: await saqla();. Shunda "Saqlandi!" faqat haqiqatan saqlangandan keyin chiqadi, xato esa catch ga tushadi.

5.2 Qachon await siz chaqirish mumkin

Ba'zan natijani kutish haqiqatan kerak emas: masalan, statistika yuborish. Lekin xatoni baribir kimdir ushlashi kerak:

js
statistikaYubor(sahifa).catch((xato) => console.warn(xato.message));

Qoida: har Promise yo await qilinadi, yo return qilinadi, yo .catch() oladi. Katta loyihalarda buni maxsus tekshiruvchi vosita kuzatadi. ESLint — kodni avtomatik tekshiradigan dastur, TypeScript — JavaScript'ning turlar qo'shilgan varianti. Ularning no-floating-promises qoidasi "suzib yurgan" Promise'ni topib, ogohlantiradi. Ikkalasi 15–16-qismlarda; hozir bilish shart emas.

Yana bir belgi. async funksiya natijasini await siz chiqarsangiz, konsolda qiymat emas, Promise ko'rinadi:

js
async function narxniOl() {
  await null;
  return 35000;
}

const narx = narxniOl();
console.log(narx);

Konsolda:

text
Promise { <pending> }

Konsolda Promise { <pending> } ko'rsangiz — deyarli doim qayerdadir await unutilgan.

Tekshirib ko'ring: Ofitsiant Otabekning ilovasida async function buyurtmaniYubor() bor. Tugma tinglovchisida u buyurtmaniYubor(); ekranniTozala(); deb chaqirilgan. Buyurtma yuborilmay qolsa, Otabek buni biladimi?

Javob

Yo'q. await yo'q — Promise suzib yuradi. Ekran darhol tozalanadi, yuborish xatosi esa hech qayerda ko'rsatilmaydi: brauzer konsolga Uncaught (in promise) yozadi, Otabek esa uni ko'rmaydi. Tuzatish: tinglovchini async qilib, try { await buyurtmaniYubor(); ekranniTozala(); } catch (xato) { ... } — xatoni ekranda ko'rsatish.

6. await qayerda ishlaydi

6.1 Faqat async funksiya ichida

Oddiy funksiyada await — sintaksis xatosi. Kod umuman ishga tushmaydi:

js
async function narxniOl() {
  return 35000;
}
function chekYoz() {
  const narx = await narxniOl();
}

Brauzerda va oddiy skriptda:

text
SyntaxError: await is only valid in async functions and the top level bodies of modules

Tarjimasi: "await faqat async funksiyalarda va modullarning eng yuqori darajasida ishlaydi". Node'da .mjs faylda xabar boshqacha — SyntaxError: Unexpected reserved word ("kutilmagan band qilingan so'z"). Modulda await — tilning band so'zi, uni oddiy funksiyada uchratgan Node "bu yerda bu so'zni kutmagan edim" deydi. Ikkala xabarning tuzatishi bitta: await turgan funksiyaga async qo'shing.

async faqat eng yaqin funksiyaga ta'sir qiladi. async funksiya ichidagi oddiy callback'da await yozsangiz — yana shu xato:

js
async function hammasiniOl(taomlar) {
  taomlar.forEach((taom) => {
    const narx = await narxniSora(taom); // SyntaxError
  });
}

Callback'ni async qilsangiz, xato yo'qoladi — lekin yangi, ancha ayyorroq muammo paydo bo'ladi. Uni keyingi darsda, Ketma-ket va parallel bajarish da ko'ramiz.

6.2 Modulning eng yuqori darajasi

Xabardagi ikkinchi qism — "modullarning eng yuqori darajasi". ES modulda (.mjs, type="module") await ni funksiyadan tashqarida ham yozish mumkin. Bu top-level await deyiladi va Dinamik import() va top-level await darsida o'rganiladi — hozir bilish shart emas. Shu paytgacha kodimizda bitta joy await siz qoladi — eng tashqi chaqiruv: bronJarayoni(4);.

6.3 Asinxron IIFE

Oddiy skriptda (modul bo'lmagan) await ni darhol ishlatish kerak bo'lsa, eski usul bor — asinxron IIFE. IIFE va funksiya obyekt sifatida darsida "(async () => { ... })() shaklini async/await darsida ko'ramiz" degan edik:

js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

(async () => {
  console.log("Kassa ochilmoqda...");
  await kut(200);
  console.log("Kassa ochiq");
})();

Konsolda:

text
Kassa ochilmoqda...
Kassa ochiq

Async arrow funksiya yaratiladi va shu zahoti chaqiriladi. Uning ichida await erkin ishlaydi. Eski kodda va Node skriptlarida bu shaklni tez-tez uchratasiz.

IIFE darsidagi tuzoqni eslang: oldingi qator ; siz tugasa va keyingi qator ( bilan boshlansa, JavaScript ikkalasini bitta ifoda deb o'qiydi va oldingi qiymatni funksiya kabi chaqirmoqchi bo'ladi. Asinxron IIFE'da ham xuddi shunday. Shuning uchun ba'zi kodlarda boshida nuqta-vergulli ;(async () => { ... })(); ko'rinishini uchratasiz.

Tekshirib ko'ring: IIFE ichidagi await kut(200) butun skriptni 200 ms to'xtatadimi? IIFE'dan keyin console.log("keyingi qator") bo'lsa, u qachon chiqadi?

Javob

Yo'q, faqat IIFE'ning o'zi to'xtaydi. "keyingi qator" "Kassa ochilmoqda..." dan keyin, lekin "Kassa ochiq" dan oldin chiqadi: await da funksiya stekdan chiqadi va skript davom etadi.

6.4 await using

Resurslarni aniq boshqarish: using darsida await using shaklini ko'rgan edik — "await ni 11-qismda o'rganamiz" deb. Endi uni to'liq tushunamiz: blok tugaganda resursning [Symbol.asyncDispose]() metodi chaqiriladi va u qaytargan Promise kutiladi. Buni faqat async funksiya (yoki modul) ichida qilish mumkin — chunki kutish kerak.

js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

function ulanishOch(nomi) {
  console.log(`${nomi}: ochildi`);
  return {
    async [Symbol.asyncDispose]() {
      await kut(100);
      console.log(`${nomi}: yopildi`);
    },
  };
}

async function hisobotYoz() {
  await using baza = ulanishOch("Baza");
  console.log("Hisobot yozilmoqda");
}

hisobotYoz().then(() => console.log("Tugadi"));

Konsolda:

text
Baza: ochildi
Hisobot yozilmoqda
Baza: yopildi
Tugadi

"Tugadi" faqat baza yopilgandan keyin chiqdi: hisobotYoz ning Promise'i yopish tugashini kutdi. [Symbol.asyncDispose] ning o'zi ham async metod — u ichida await qiladi. Blok Node 24 da sinalgan; brauzerlarda bu imkoniyat hali hammasida yo'q.

7. Ko'p uchraydigan xatolar

7.1 await ni unutish

«Suzib yurgan» Promise bo'limidagi xato. Belgilari: konsolda Promise { <pending> }, "Saqlandi!" kabi xabarlar juda erta chiqadi, try/catch xatoni ushlamaydi. Yana bir ayyor ko'rinishi — shartda:

js
if (stolBormi(4)) { ... } // doim true!

stolBormi — async funksiya, u Promise qaytaradi. Promise esa obyekt — doim truthy (Boolean va truthy/falsy). false qaytsa ham shart bajariladi. Tuzatish: if (await stolBormi(4)).

7.2 async ni "parallel" yoki "fon"da ishlaydi deb o'ylash

async funksiya alohida thread'da — boshqa "ishchi"da (Sinxron va asinxron kod) — ishlamaydi. U birinchi await gacha oddiy, sinxron bajariladi. Ichida og'ir sinxron sikl bo'lsa — sahifa baribir qotadi, xuddi Promise asoslari dagi Sardorning hisobidek. async faqat kutishni samarali qiladi, hisobni emas.

7.3 Har qatorga try/catch

js
let stol;
try { stol = await stolTop(4); } catch (x) { console.log(x); }
let bron;
try { bron = await bronQil(stol); } catch (x) { console.log(x); }

Birinchi qadam xato bersa, ikkinchisi undefined stol bilan baribir bajariladi. Tuzatish: bog'liq qadamlarni bitta try ga oling — xato bo'lsa, qolgani o'tkazib yuborilsin. Alohida try faqat o'sha qadamning xatosiga boshqacha munosabat (zaxira, qayta urinish) kerak bo'lganda.

7.4 Mustaqil ishlarni ketma-ket await qilish

js
const osh = await narxniSora("osh");
const manti = await narxniSora("manti");

Bu to'g'ri ishlaydi, lekin sekin: "manti" so'rovi "osh" javobini kutib turadi, garchi ular bir-biriga bog'liq bo'lmasa ham. Ikkalasi 200 ms dan bo'lsa — jami 400 ms. Buni qanday 200 ms ga tushirish — keyingi darsning asosiy mavzusi.

8. Mashqlar

1-mashq (oson): Zanjirdan await ga

Promise zanjiri dagi choy zanjirini async funksiya bilan qayta yozing. suvQaynat, choySol, damla — o'zgarmaydi. choyTayyorla() nomli async funksiya ularni ketma-ket await qilsin, natijani chiqarsin, xato bo'lsa — try/catch bilan Xato: ... deb yozsin.

Yechim
js
function suvQaynat() {
  return new Promise((resolve) => {
    setTimeout(() => resolve("qaynoq suv"), 100);
  });
}
function choySol(suv) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`${suv} + ko'k choy`), 100);
  });
}
function damla(choynak) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`${choynak} (damlandi)`), 100);
  });
}

async function choyTayyorla() {
  try {
    const suv = await suvQaynat();
    const choynak = await choySol(suv);
    const choy = await damla(choynak);
    console.log("Tayyor:", choy);
  } catch (xato) {
    console.log("Xato:", xato.message);
  }
}

choyTayyorla();

Konsolda:

text
Tayyor: qaynoq suv + ko'k choy (damlandi)

Har oraliq natija o'z nomiga ega: suv, choynak, choy. Zanjirda ular faqat then parametrlari edi.

2-mashq (o'rta): Tartibni oldindan ayting

Avval qog'ozda yozing, keyin tekshiring. Ishora: async funksiya birinchi await gacha sinxron; await dan keyingi qism — microtask.

js
async function birinchi() {
  console.log("B");
  await null;
  console.log("D");
}

console.log("A");
birinchi();
new Promise((resolve) => {
  console.log("C");
  resolve();
}).then(() => console.log("E"));
console.log("F");
Yechim

Konsolda:

text
A
B
C
F
D
E

Sinxronlar: A, B (birinchi ichida, await gacha), C (executor), F. await null — birinchi ning davomi microtask navbatiga birinchi bo'lib tushdi. Keyin then callback'i — ikkinchi. Shuning uchun D, keyin E.

3-mashq (qiyin): Qayta urinish — sikl bilan

Promise zanjiri dagi 3-mashqda qaytaUrin ni rekursiya bilan yozgan edik. Endi uni async funksiya, for sikli va try/catch bilan qayta yozing: kurs/mashqlar/11/07-async/qaytaUrin.mjs. Qo'shimcha talab: urinishlar orasida 100 * urinish ms kutilsin (birinchidan keyin 100, ikkinchidan keyin 200 ...) — kut yordamchisi bilan. Sinov — o'sha ishonchsizServer.

Yechim
js
function kut(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

let chaqiruv = 0;
function ishonchsizServer() {
  chaqiruv++;
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (chaqiruv < 3) reject(new Error(`${chaqiruv}-urinish xato`));
      else resolve(`${chaqiruv}-urinishda narx: 28000`);
    }, 100);
  });
}

async function qaytaUrin(ish, marta) {
  for (let urinish = 1; ; urinish++) {
    try {
      return await ish();
    } catch (xato) {
      console.log("Xato:", xato.message);
      if (urinish >= marta) throw xato;
      console.log(`${100 * urinish} ms kutamiz`);
      await kut(100 * urinish);
    }
  }
}

async function asosiy() {
  try {
    const natija = await qaytaUrin(ishonchsizServer, 5);
    console.log(natija);
  } catch (xato) {
    console.log("Taslim:", xato.message);
  }
}

asosiy();

Konsolda:

text
Xato: 1-urinish xato
100 ms kutamiz
Xato: 2-urinish xato
200 ms kutamiz
3-urinishda narx: 28000

Uchta muhim joy:

  • return await ish() — try ichida! Oddiy return ish() bo'lsa, rad etish catch ga tushmasdi va birinchi xatodayoq tashqariga chiqardi («return va return await farqi» bo'limi).
  • for (let urinish = 1; ; urinish++) — sikl shartsiz: undan return (muvaffaqiyat) yoki throw (urinishlar tugadi) bilan chiqiladi.
  • await kut(...) sikl ichida — siklni ham to'xtatadi. Sinxron kodda bunday "kutish" uchun bo'sh sikl kerak bo'lardi va sahifa qotardi (Sinxron va asinxron kod). Bu yerda esa kutish paytida stek bo'sh.
bash
git add 11/07-async/qaytaUrin.mjs
git commit -m "11/07: qaytaUrin — async/await va for bilan"

9. Real ishda

  • Asosiy shakl. Bugungi frontend va backend kodning katta qismi async/await da: React'da ma'lumot yuklash, Express va NestJS'da so'rov ishlovchilari, ma'lumotlar bazasi so'rovlari (await db.query(...)). Tarmoq so'rovi ham shunday ko'rinadi: const javob = await fetch(url) — fetch asoslari da o'rganasiz.
  • then hamon bor. Bir qatorli o'zgartirishlar, catch bilan zaxira qiymat, kutubxona ichlari — zanjirni ham o'qiy olishingiz kerak. Ikkalasi bitta Promise ustida ishlaydi va aralash yozilishi mumkin: const narx = await narxniSora("osh").catch(() => 28000);.
  • Kod sharhi. "Bu yerda await unutilmaganmi?", "Bu xato kimga ketadi?" — asinxron kodli PR'larda eng ko'p beriladigan savollar.
  • Intervyu. "async funksiya nima qaytaradi?", "await thread'ni bloklaydimi?", "Bu kodning chiqish tartibi qanday?" (async + setTimeout + then aralash), "return va return await farqi" — juda tez-tez.

Xulosa

  • async funksiya doim Promise qaytaradi: return — bajarilish, throw — rad etish.
  • await promise faqat shu funksiyani to'xtatadi; chaqiruvchi davom etadi, stek bo'shaydi. Davomi — microtask.
  • async funksiya birinchi await gacha sinxron ishlaydi; await Promise bo'lmagan qiymatda ham to'xtaydi.
  • Rad etilgan await — throw: uni try/catch/finally ushlaydi; try ichida return await yozing.
  • Har Promise yo await, yo return, yo .catch() qilinsin — aks holda u "suzib yuradi" va xatosi yo'qoladi.
  • await faqat async funksiya ichida (yoki modulning yuqori darajasida) ishlaydi.

Keyingi dars: Ketma-ket va parallel bajarish — mustaqil ishlarni bir vaqtda boshlab, Promise.all bilan kutish; sikldagi await va forEach + async tuzog'i.

Manbalar

  • ECMAScript spetsifikatsiyasi: "Async Function Definitions", "Await" — tc39.es/ecma262
  • MDN: "async function", "await", "Using promises" — developer.mozilla.org
  • V8 blogi: "Faster async functions and promises" (await qadamlari) — v8.dev
  • typescript-eslint: "no-floating-promises" qoidasi — typescript-eslint.io
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript async / await: asinxron kodni sinxron kabi yozish — IlmHamroh