fetch metodi yuklash jarayonini kuzatish imkonini beradi.
Diqqat qiling: hozirda fetch uchun yuborish jarayonini kuzatish imkoni yo’q. Bu maqsad uchun XMLHttpRequest dan foydalaning, uni keyinroq ko’rib chiqamiz.
Yuklash jarayonini kuzatish uchun response.body xususiyatidan foydalanishimiz mumkin. Bu ReadableStream – kelganda body ni qism-qism taqdim etadigan maxsus obyekt. Readable stream’lar Streams API spetsifikatsiyasida tasvirlangan.
response.text(), response.json() va boshqa metodlardan farqli o’laroq, response.body o’qish jarayoni ustidan to’liq nazoratni beradi va biz istalgan paytda qancha iste’mol qilinganini hisoblashimiz mumkin.
response.body dan javobni o’qiydigan kodning eskizi:
// response.json() va boshqa metodlar o'rniga
const reader = response.body.getReader();
// body yuklanayotganda cheksiz siklda
while(true) {
// oxirgi qism uchun done true bo'ladi
// value - qism baytlarining Uint8Array si
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`${value.length} bayt qabul qilindi`)
}
await reader.read() chaqiruvining natijasi ikkita xususiyatga ega obyekt:
done– o’qish tugallangandatrue, aks holdafalse.value– baytlarning typed array:Uint8Array.
Streams API shuningdek for await..of sikli bilan ReadableStream ustida asinxron iteratsiyani tasvirlaydi, lekin u hali keng qo’llab-quvvatlanmaydi (brauzer muammolariga qarang), shuning uchun biz while siklini ishlatamiz.
Yuklash tugagunicha, ya’ni done true bo’lgunicha, biz siklda javob qismlarini qabul qilamiz.
Jarayonni yozib qo’yish uchun, har bir qabul qilingan value fragment uchun uning uzunligini hisoblagichga qo’shishimiz kerak.
Mana to’liq ishlaydigan misol, u javobni oladi va konsolda jarayonni yozadi, keyinroq batafsilroq tushuntirishlar keladi:
// 1-qadam: fetch'ni boshlash va reader olish
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
const reader = response.body.getReader();
// 2-qadam: umumiy uzunlikni olish
const contentLength = +response.headers.get('Content-Length');
// 3-qadam: ma'lumotlarni o'qish
let receivedLength = 0; // hozirda qabul qilingan baytlar soni
let chunks = []; // qabul qilingan ikkilik qismlar massivi (body ni tashkil etadi)
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
console.log(`${contentLength} dan ${receivedLength} qabul qilindi`)
}
// 4-qadam: qismlarni yagona Uint8Array ga birlashtirish
let chunksAll = new Uint8Array(receivedLength); // (4.1)
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position); // (4.2)
position += chunk.length;
}
// 5-qadam: stringga dekodlash
let result = new TextDecoder("utf-8").decode(chunksAll);
// Tugadi!
let commits = JSON.parse(result);
alert(commits[0].author.login);
Buni qadam-baqadam tushuntiraylik:
-
Biz
fetchni odatdagidek bajaramiz, lekinresponse.json()ni chaqirish o’rniga, stream readerresponse.body.getReader()ni olamiz.Diqqat qiling, biz bir xil javobni o’qish uchun ikkala metoddan ham foydalana olmaymiz: natijani olish uchun yoki reader yoki response metodidan foydalaning.
-
O’qishdan oldin,
Content-Lengthheader’idan to’liq javob uzunligini bilishimiz mumkin.U cross-origin so’rovlar uchun mavjud bo’lmasligi mumkin (Fetch: Cross-Origin So'rovlari bobiga qarang) va, texnik jihatdan, server uni o’rnatishi shart emas. Lekin odatda u o’rnida turadi.
-
Tugagunicha
await reader.read()ni chaqiring.Biz javob qismlarini
chunksmassivida to’playmiz. Bu muhim, chunki javob iste’mol qilingandan keyin, uniresponse.json()yoki boshqa yo’l bilan “qayta o’qish” imkoni bo’lmaydi (sinab ko’ring, xatolik bo’ladi). -
Oxirida bizda
chunks–Uint8Arraybayt qismlari massivi bor. Biz ularni yagona natijaga birlashtirishimiz kerak. Afsuski, ularni birlashtiruvchi yagona metod yo’q, shuning uchun buni amalga oshiradigan kod bor:- Biz
chunksAll = new Uint8Array(receivedLength)yaratamiz – birlashtirilgan uzunlikka ega bir xil turdagi massiv. - Keyin har bir
chunkni birin-ketin nusxalash uchun.set(chunk, position)metodidan foydalanamiz.
- Biz
-
Bizda natija
chunksAllda bor. Bu bayt massivi, string emas.String yaratish uchun bu baytlarni talqin qilishimiz kerak. O’rnatilgan TextDecoder aynan shuni qiladi. Keyin kerak bo’lsa uni
JSON.parseqilishimiz mumkin.Agar bizga string o’rniga ikkilik kontent kerak bo’lsa-chi? Bu yanada oddiy. 4 va 5-qadamlarni barcha qismlardan
Blobyaratadigan yagona qator bilan almashtiring:let blob = new Blob(chunks);
Oxirida bizda natija (string yoki blob, qaysi biri qulay bo’lsa) va jarayonda progress-tracking bor.
Yana bir bor, diqqat qiling, bu yuborish jarayoni uchun emas (fetch bilan hozir yo’li yo’q), faqat yuklash jarayoni uchun.
Bundan tashqari, agar o’lcham noma’lum bo’lsa, siklda receivedLength ni tekshirishimiz va u ma’lum chegaraga yetganda uni to’xtatishimiz kerak. Shunda chunks xotirani to’ldirmaydi.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)