Tarmoq so'rovlari

Fetch: yuklanish jarayoni

Katta hajmdagi ma'lumotni yuklab olayotganda (masalan, katta fayl yoki video), foydalanuvchiga necha foiz yuklanganini ko'rsatish foydali. fetch buni response.body orqali โ€” oqim (stream) sifatida o'qish imkonini beradi.

Eslatma: fetch yuklab olish (download) jarayonini kuzatishga imkon beradi, ammo yuklab jo'natish (upload) jarayonini kuzata olmaydi โ€” buning uchun keyingi darsdagi XMLHttpRequest kerak bo'ladi.

response.body โ€” ReadableStream

Oldingi darslarda javob tanasini response.json() yoki response.text() bilan bir martaga o'qidik. Ammo response.body โ€” bu ReadableStream obyekti: ma'lumotni bo'lak-bo'lak (chunk) o'qishga imkon beradigan maxsus oqim.

Aynan shu bo'laklarni sanab, umumiy hajmga solishtirib, yuklanish foizini hisoblashimiz mumkin.

getReader() bilan o'qish

Oqimdan o'qish uchun undan reader (o'quvchi) olamiz va read() metodini takroran chaqiramiz. Har chaqiruv bitta bo'lakni qaytaradi:

let response = await fetch('https://example.com/big-file');

const reader = response.body.getReader();

while (true) {
  const { done, value } = await reader.read();

  if (done) {
    break; // oqim tugadi
  }

  // value โ€” Uint8Array turidagi navbatdagi bo'lak
  console.log('Bo'lak olindi, bayt: ' + value.length);
}

reader.read() promise qaytaradi va u ikki maydonli obyekt bilan bajariladi:

Content-Length โ€” umumiy hajm

Foizni hisoblash uchun umumiy hajmni bilishimiz kerak. Buni server Content-Length sarlavhasida yuboradi:

let response = await fetch(url);

const contentLength = response.headers.get('Content-Length');
const total = parseInt(contentLength, 10);

console.log('Umumiy hajm: ' + total + ' bayt');
Diqqat: Content-Length har doim ham mavjud bo'lavermaydi โ€” masalan, server ma'lumotni siqilgan (gzip) yoki chunked ko'rinishda yuborsa, u yo'q yoki noaniq bo'lishi mumkin. Shuning uchun kodda uning yo'qligini ham hisobga oling.

Progressni to'liq hisoblash

Endi hammasini birlashtiramiz: umumiy hajmni olamiz, bo'laklarni o'qib, qabul qilingan baytlarni sanaymiz va foizni chiqaramiz:

async function yuklabOl(url) {
  let response = await fetch(url);

  const reader = response.body.getReader();

  // Umumiy hajm (agar mavjud bo'lsa)
  const contentLength = +response.headers.get('Content-Length');

  let receivedLength = 0;    // qabul qilingan baytlar
  let chunks = [];           // bo'laklar massivi

  while (true) {
    const { done, value } = await reader.read();

    if (done) {
      break;
    }

    chunks.push(value);
    receivedLength += value.length;

    // Progressni chiqaramiz
    if (contentLength) {
      let percent = Math.round((receivedLength / contentLength) * 100);
      console.log('Yuklandi: ' + percent + '%');
    } else {
      console.log('Yuklandi: ' + receivedLength + ' bayt');
    }
  }

  return chunks;
}

Bu yerda har bir bo'lak chunks massiviga saqlanadi va receivedLength oshib boradi. Foiz โ€” qabul qilingan / umumiy * 100 formulasi bilan hisoblanadi.

Bo'laklarni birlashtirish

Barcha bo'laklar o'qib bo'lingach, ularni bitta massivga birlashtirib, so'ng matnga (yoki JSON'ga) aylantirishimiz mumkin:

// chunks โ€” Uint8Array bo'laklari massivi

// 1) Barcha baytlarni bitta massivga birlashtiramiz
let chunksAll = new Uint8Array(receivedLength);
let position = 0;

for (let chunk of chunks) {
  chunksAll.set(chunk, position);
  position += chunk.length;
}

// 2) Baytlarni matnga aylantiramiz
let result = new TextDecoder('utf-8').decode(chunksAll);

// 3) Agar JSON bo'lsa, tahlil qilamiz
let data = JSON.parse(result);
console.log(data);
TextDecoder โ€” baytlarni (Uint8Array) matnga aylantiradigan o'rnatilgan brauzer vositasi. UTF-8 kodlashda emoji va o'zbekcha harflar to'g'ri o'qiladi.

Nima uchun oddiy usul yetarli emas?

Agar progress kerak bo'lmasa, oddiygina await response.json() yozish yetarli โ€” u ancha soddaroq. ReadableStream faqat yuklanish jarayonini kuzatish kerak bo'lganda ishlatiladi:

// Progress kerak bo'lmasa โ€” sodda:
let response = await fetch(url);
let data = await response.json();

// Progress kerak bo'lsa โ€” reader bilan:
let reader = response.body.getReader();
// ...bo'lak-bo'lak o'qish va foiz hisoblash
Amaliyotda ReadableStream katta fayllar, video yoki uzoq davom etadigan yuklashlar uchun ajratilgan. Kichik JSON javoblar uchun oddiy response.json() to'g'ri tanlov.

Xulosa