Seriya: JavaScript Basics Dars 60

Fetch API

fetch() nima ekani va XMLHttpRequest'dan nega ustunligi, u Promise+Microtask+Event Loop mashinasini real tarmoq so'roviga qanday qo'llashi, Response obyektining ikki bosqichli dizayni, fetch() HTTP xatolarni nega avtomatik reject qilmasligi, va CORS/Same-Origin Policy.

60-dars

Fetch API

fetch() — brauzerdan serverga tarmoq so'rovi yuborish va javobni olish uchun standart, zamonaviy usul. U — Promise qaytaradigan, brauzer taqdim qiladigan Web API (avvalda ko'rgan setTimeout kabi — V8'ning o'zi emas, brauzer ta'minlaydi).

fetch('https://api.example.com/users')
  .then(response => response.json())
  .then(data => console.log(data));

Yoki async/await bilan:

async function getUsers() {
  const response = await fetch('https://api.example.com/users');
  const data = await response.json();
  console.log(data);
}

1. Nega kerak bo'lgan — undan oldin nima bor edi?

fetch()dan oldin, tarmoq so'rovlari XMLHttpRequest (XHR) orqali qilingan (1999, Microsoft tomonidan, keyinchalik standartlashtirilgan). XHR — callback-asosli, va uning API'si noqulay edi:

// Eski usul — XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/users');
xhr.onload = () => {
  if (xhr.status >= 200 && xhr.status < 300) {
    console.log(JSON.parse(xhr.responseText));
  } else {
    console.log('Xato:', xhr.status);
  }
};
xhr.onerror = () => console.log('Tarmoq xatosi');
xhr.send();

Muammolar: callback-asosli (avvalda ko'rgan Callback Hell xavfi), xato boshqarish chalkash (onerror, onload ichida status tekshirish, va h.k.), Promise bilan tabiiy integratsiya yo'q. 2015-yilda, ES6/Promise bilan bir vaqtda, fetch() — shu muammolarni yechish uchun, Promise-asosli, zamonaviy alternativa sifatida kiritildi.


2. fetch() — Web API sifatida, Event Loop bilan bog'liqligi

Bu — avvalgi bosqich bilimi bilan to'g'ridan-to'g'ri bog'liq. fetch() chaqirilganda:

  1. V8 — fetch() funksiyasini darhol qaytaradi, u pending Promise'ni beradi (Call Stack band bo'lib qolmaydi)
  2. Haqiqiy tarmoq so'rovi — V8'dan tashqarida, brauzerning **tarmoq qatlami (network stack)**ga topshiriladi (bu — Blink'dan ham pastroq, operatsion tizim darajasidagi tarmoq modullariga yaqin qism)
  3. Brauzer server bilan TCP ulanish, DNS lookup, TLS handshake (agar HTTPS bo'lsa) kabi jarayonlarni orqa fonda bajaradi — bularning hech biri JS thread'ini band qilmaydi
  4. Javob kelgach, brauzer Promise'ni resolve qilishni Microtask Queue'ga qo'yadi (Microtask vs Macrotask — eslatma: fetch natijasi microtask sifatida ishlanadi, setTimeout kabi macrotask emas)
  5. Event Loop — Call Stack bo'shagach, shu microtask'ni oladi, va sizning .then() yoki awaitdan keyingi kod bajariladi

Ya'ni: fetch() — avvalda o'rgangan butun asinxron mashinaning to'g'ridan-to'g'ri amaliy qo'llanilishi. Hech qanday yangi mexanizm yo'q — faqat Promise + Web API + Event Loop, endi real tarmoq so'roviga qo'llangan holda.


3. Response obyekti — nega ikki bosqichli (fetch + .json())

Ko'plab yangi boshlovchilar shu joyda adashadi:

const response = await fetch(url);  // 1-bosqich
const data = await response.json(); // 2-bosqich — nega yana await?

Sabab: fetch()ning Promise'i — javob to'liq kelishini kutmaydi, faqat header'lar kelishi bilanoq resolve bo'ladi (status kod, content-type va h.k. allaqachon ma'lum bo'ladi). Lekin javobning tanasi (body) — katta bo'lishi mumkin (masalan, 50MB fayl), va u stream sifatida, bo'lak-bo'lak keladi.

response.json() — shu stream'ni to'liq o'qib bo'lguncha kutadigan, alohida asinxron operatsiya, va u ham o'zining Promise'ini qaytaradi. Bu — ikki bosqichli dizayn: birinchisi "javob boshlandimi" (tez), ikkinchisi "javob tanasi tayyor" (sekinroq, hajmga bog'liq).

Response obyektida boshqa metodlar ham bor, formatga qarab:

await response.json();  // JSON'ga parse qilish
await response.text();  // oddiy matn
await response.blob();  // binary (rasm, video, fayl)
await response.arrayBuffer(); // xom bayt darajasida

4. fetch() — HTTP xatolarni "xato" deb hisoblamaydi!

Bu — eng ko'p uchraydigan tuzoq:

const response = await fetch('https://api.example.com/notfound');
console.log(response.ok);     // false
console.log(response.status); // 404
// LEKIN — .catch() ISHGA TUSHMAYDI, xato tashlanmagan!

fetch()ning Promise'i — faqat tarmoq darajasida muammo bo'lsa (internet yo'q, DNS topilmadi, CORS bloklandi) reject bo'ladi. HTTP 404, 500 kabi status kodlar — brauzer nuqtai nazaridan, "server javob berdi" degani, hatto javob "xato" bo'lsa ham. Shuning uchun to'g'ri kod har doim response.okni tekshirishi kerak:

async function getUsers() {
  const response = await fetch('https://api.example.com/users');
  if (!response.ok) {
    throw new Error(`HTTP xato: ${response.status}`);
  }
  return response.json();
}

Bu — avvalda ko'rgan Error handling async'da mavzusi bilan to'g'ridan-to'g'ri bog'liq: fetch()ning o'zi xato tashlamagani uchun, dasturchi qo'lda tekshirib, kerak bo'lsa o'zi throw qilishi shart, aks holda xatolik "yutilib" ketadi.


5. fetch() konfiguratsiyasi — ikkinchi argument

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123'
  },
  body: JSON.stringify({ name: 'Ali', age: 25 })
});
  • method — GET (standart), POST, PUT, DELETE, va h.k.
  • headers — so'rov bilan boradigan meta-ma'lumot
  • body — yuboriladigan ma'lumot (JSON, FormData, Blob bo'lishi mumkin)

6. CORS — brauzer darajasidagi muhim to'siq

fetch() ishlatilganda, brauzer avtomatik ravishda Same-Origin Policyni qo'llaydi (Storage API'lar mavzusida ko'rgan origin izolyatsiyasi bilan bog'liq). Agar siz https://myapp.comdan turib https://api.other.comga so'rov yuborsangiz, va api.other.com server o'z javobida Access-Control-Allow-Origin header'ini qo'shmagan bo'lsa — brauzer javobni butunlay bloklaydi, hatto server to'g'ri javob qaytargan bo'lsa ham:

Access to fetch at 'https://api.other.com/data' from origin 'https://myapp.com'
has been blocked by CORS policy

Bu — brauzerning xavfsizlik mexanizmi: aks holda, zararli sayt sizning brauzeringiz orqali (sizning cookie'laringiz bilan) boshqa saytlarga so'rov yuborib, ma'lumot o'g'irlashi mumkin bo'lardi. Muhim nuance: so'rov serverga baribir yetib boradi (server uni qayta ishlaydi), lekin javob brauzerda JS'ga ko'rinmaydi — bloklash browser tomonida, javob qaytib kelgandan keyin sodir bo'ladi.


Xulosa

fetch() — Promise-asosli Web API, u avvalda o'rgangan asinxron mashinani (Promise + Microtask + Event Loop) real tarmoq so'rovlariga qo'llaydi, ikki bosqichli javob (header keldi → keyin body o'qildi), HTTP xatolarni avtomatik reject qilmaydi, va Same-Origin Policy/CORS orqali xavfsizlik chegaralanadi.