Promise, async/await

Promise zanjiri

Ko'pincha bir nechta asinxron ishni ketma-ket bajarishimiz kerak bo'ladi: masalan, ma'lumot yuklab, uni qayta ishlab, so'ng saqlash. Promise buni zanjir (chaining) orqali chiroyli hal qiladi โ€” callback jahannamisiz, tekis kod bilan. Ushbu darsda Promise zanjirini o'rganamiz.

Zanjirning asosiy g'oyasi

Promise zanjiri quyidagi g'oyaga asoslanadi: promise.then(...) chaqiruvi yangi Promise qaytaradi. Demak, uning ustiga yana .then ulashimiz mumkin. Va yana. Va yana โ€” natijada zanjir hosil bo'ladi:

new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
})
  .then(function (result) {
    console.log(result); // 1
    return result * 2;
  })
  .then(function (result) {
    console.log(result); // 2
    return result * 2;
  })
  .then(function (result) {
    console.log(result); // 4
    return result * 2;
  });

// Konsolda: 1, keyin 2, keyin 4

G'oya shunda: har bir .thendan return qilingan qiymat keyingi .thenga uzatiladi. Shunday qilib, natija zanjir bo'ylab bosqichma-bosqich "oqib" boradi.

Bu ishlashining sababi: .then har doim yangi Promise qaytaradi. Uning callback'idan qaytgan qiymat esa shu yangi Promise'ning natijasiga aylanadi.

Xato: zanjir emas, ko'p mustaqil .then

Yangi boshlovchilar ko'p qiladigan xato โ€” bitta Promise'ga bir nechta .thenni alohida ulash va uni zanjir deb o'ylash. Bu butunlay boshqa narsa:

const promise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
});

// BU ZANJIR EMAS! Uch mustaqil .then bitta promise'ga ulangan
promise.then(function (result) {
  console.log(result); // 1
  return result * 2;
});
promise.then(function (result) {
  console.log(result); // 1  (2 emas!)
  return result * 2;
});
promise.then(function (result) {
  console.log(result); // 1  (4 emas!)
});

// Konsolda: 1, 1, 1
Bu yerda uchala .then ham bitta va o'sha Promise'ni mustaqil qayta ishlaydi, natijani bir-biriga uzatmaydi. Shuning uchun uchalasi ham 1 chiqaradi. Zanjir bo'lishi uchun .thenlar bir-birining natijasiga ulanishi kerak (nuqta orqali ketma-ket).

.then ichida Promise qaytarish

Zanjirning eng kuchli jihati: .thenning callback'idan oddiy qiymat emas, balki yangi Promise qaytarish mumkin. Bunday holda zanjir shu yangi Promise hal bo'lguncha kutadi, so'ng uning natijasi bilan davom etadi.

new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
})
  .then(function (result) {
    console.log(result); // 1

    // Oddiy qiymat emas, YANGI Promise qaytaramiz:
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        resolve(result * 2);
      }, 1000);
    });
  })
  .then(function (result) {
    // Bu .then yuqoridagi yangi Promise hal bo'lgach ishlaydi
    console.log(result); // 2

    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        resolve(result * 2);
      }, 1000);
    });
  })
  .then(function (result) {
    console.log(result); // 4
  });

// Har bosqich 1 sekund kutadi: 1 (1s), 2 (2s), 4 (3s)

Aynan shu imkoniyat โ€” .thendan Promise qaytarish โ€” bizga ketma-ket asinxron ishlarni tekis yozishga imkon beradi. Har bir bosqich oldingisi tugagach boshlanadi.

Agar .thendan Promise qaytarsangiz, JavaScript uni "kutib" beradi. Agar oddiy qiymat qaytarsangiz โ€” u darhol keyingi bosqichga uzatiladi. Ikkala holat ham bir xil sintaksis bilan ishlaydi.

Amaliy misol: ketma-ket skript yuklash

Oldingi darslarda callback bilan uch skriptni ketma-ket yuklaganimizni eslang โ€” piramida hosil bo'lgandi. Promise bilan ayni ishni tekis yozamiz. loadScript endi Promise qaytaradi deb faraz qilaylik:

// loadScript(src) endi Promise qaytaradi deb faraz qilaylik

loadScript("1.js")
  .then(function () {
    return loadScript("2.js");
  })
  .then(function () {
    return loadScript("3.js");
  })
  .then(function () {
    console.log("Uchala skript ham ketma-ket yuklandi!");
  });

Callback varianti bilan solishtiring: u yerda kod o'ngga qarab chuqurlashardi (piramida). Bu yerda esa zanjir tekis โ€” har bir .then bir xil chuqurlikda, pastga qarab o'qiladi. Bu Promise zanjirining asosiy yutug'i.

Aynan shu "tekislik" tufayli Promise callback jahannamini yechadi. Kod chapdan o'ngga emas, yuqoridan pastga o'qiladi โ€” xuddi oddiy sinxron kod kabi.

Zanjirda qiymatlarni uzatishni tushunish

Sodda sinxron misol bilan "qiymat zanjir bo'ylab uzatiladi" g'oyasini mustahkamlaymiz. Bu yerda darhol hal bo'lgan Promise ishlatilgan, shuning uchun natijalar konsolda ko'rinadi:

chaining.js
// natija shu yerda chiqadi

Promise.resolve(5) โ€” darhol 5 qiymati bilan bajarilgan Promise yaratadi. So'ng har bosqich oldingisining natijasini oladi, o'zgartiradi va keyingisiga uzatadi: 5 → 15 → 30.

Promise.resolve(value) โ€” tayyor (fulfilled) Promise yaratishning qisqa usuli. Zanjirni boshlash yoki qiymatni Promise ichiga "o'rash" uchun qulay.

Xulosa