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
fetch
ni 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-Length
header’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
chunks
massivida 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
–Uint8Array
bayt 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
chunk
ni birin-ketin nusxalash uchun.set(chunk, position)
metodidan foydalanamiz.
- Biz
-
Bizda natija
chunksAll
da 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.parse
qilishimiz mumkin.Agar bizga string o’rniga ikkilik kontent kerak bo’lsa-chi? Bu yanada oddiy. 4 va 5-qadamlarni barcha qismlardan
Blob
yaratadigan 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…)