ÐеÑод fetch дозволÑÑ Ð²ÑдÑÑежÑваÑи Ñ
Ñд заванÑаженнÑ.
ÐÑÐ´Ñ Ð»Ð°Ñка, звеÑнÑÑÑ ÑвагÑ: наÑÐ°Ð·Ñ fetch не може вÑдÑÑежÑваÑи Ñ
Ñд виванÑаженнÑ. ÐÐ»Ñ ÑÑÑÑ Ð¼ÐµÑи викоÑиÑÑовÑйÑе XMLHttpRequest, ми ÑозглÑнемо його пÑзнÑÑе.
Щоб вÑдÑÑежÑваÑи Ñ
Ñд заванÑаженнÑ, ми можемо викоÑиÑÑовÑваÑи влаÑÑивÑÑÑÑ response.body. Це ReadableStream â ÑпеÑÑалÑний обâÑкÑ, Ñкий Ð½Ð°Ð´Ð°Ñ ÑÑло вÑдповÑÐ´Ñ ÑÑагменÑами, в мÑÑÑ Ð½Ð°Ð´Ñ
одженнÑ. ÐоÑоки Ð´Ð»Ñ Ð·ÑиÑÑÐ²Ð°Ð½Ð½Ñ Ð¾Ð¿Ð¸ÑÐ°Ð½Ñ Ð² ÑпеÑиÑÑкаÑÑÑ Streams API.
Ðа вÑдмÑÐ½Ñ Ð²Ñд response.text(), response.json() Ñа ÑнÑиÑ
меÑодÑв, response.body Ð´Ð°Ñ Ð¿Ð¾Ð²Ð½Ð¸Ð¹ конÑÑÐ¾Ð»Ñ Ð½Ð°Ð´ пÑоÑеÑом зÑиÑÑваннÑ, Ñ Ð¼Ð¸ можемо пÑдÑаÑ
ÑваÑи, ÑкÑлÑки даниÑ
оÑÑимано в бÑдÑ-Ñкий моменÑ.
ÐÑÑ Ð¿Ñиклад кодÑ, Ñкий зÑиÑÑÑ Ð²ÑдповÑÐ´Ñ Ð· response.body:
// замÑÑÑÑ response.json() Ñа ÑнÑиÑ
меÑодÑв
const reader = response.body.getReader();
// неÑкÑнÑенний Ñикл, поки ÑÑло вÑдповÑÐ´Ñ Ð·Ð°Ð²Ð°Ð½ÑажÑÑÑÑÑÑ
while(true) {
// done ÑÑÐ°Ñ true в оÑÑаннÑÐ¾Ð¼Ñ ÑÑагменÑÑ
// value -- Uint8Array з байÑÑв кожного ÑÑагменÑа
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`ÐÑÑимано ${value.length} байÑ`)
}
РезÑлÑÑаÑом Ð²Ð¸ÐºÐ»Ð¸ÐºÑ await reader.read() Ñ Ð¾Ð±âÑÐºÑ Ð· двома влаÑÑивоÑÑÑми:
doneâtrue, коли зÑиÑÑÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð²ÐµÑÑено, ÑнакÑе âfalse.valueâ ÑипÑзований маÑив байÑÑв:Uint8Array.
Streams API Ñакож опиÑÑÑ Ð°ÑинÑ
ÑÐ¾Ð½Ð½Ñ ÑÑеÑаÑÑÑ Ð½Ð°Ð´ ReadableStream з Ñиклом for await..of, але вÑн Ñе не ÑиÑоко пÑдÑÑимÑÑÑÑÑÑ (дивиÑÑ Ð±Ð°Ð³Ð¸ бÑаÑзеÑÑв), ÑÐ¾Ð¼Ñ Ð¼Ð¸ викоÑиÑÑовÑÑмо Ñикл while.
Ðи оÑÑимÑÑмо ÑÑагменÑи вÑдповÑдей Ñ ÑиклÑ, поки не закÑнÑиÑÑÑÑ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ, ÑобÑо доки done не ÑÑане true.
Щоб вÑдÑÑежиÑи пÑогÑеÑ, нам пÑоÑÑо поÑÑÑбно Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ оÑÑиманого value ÑÑагменÑа додаÑи його Ð´Ð¾Ð²Ð¶Ð¸Ð½Ñ Ð´Ð¾ лÑÑилÑника.
ÐÑÑ Ð¿Ð¾Ð²Ð½Ð¸Ð¹ ÑобоÑий пÑиклад, Ñкий оÑÑимÑÑ Ð²ÑдповÑÐ´Ñ Ñа показÑÑ Ð¿ÑогÑÐµÑ Ñ ÐºÐ¾Ð½ÑолÑ, з додаÑковими поÑÑненнÑми:
// ÐÑок 1: поÑинаÑмо заванÑÐ°Ð¶ÐµÐ½Ð½Ñ fetch, оÑÑимÑÑмо поÑÑк Ð´Ð»Ñ Ð·ÑиÑÑваннÑ
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
const reader = response.body.getReader();
// ÐÑок 2: оÑÑимÑÑмо загалÑÐ½Ñ Ð´Ð¾Ð²Ð¶Ð¸Ð½Ñ
const contentLength = +response.headers.get('Content-Length');
// ÐÑок 3: зÑиÑÑÑмо данÑ
let receivedLength = 0; // кÑлÑкÑÑÑÑ Ð±Ð°Ð¹ÑÑв, оÑÑиманиÑ
на даниÑ
моменÑ
let chunks = []; // маÑив оÑÑиманиÑ
бÑнаÑниÑ
ÑÑагменÑÑв (Ñо ÑкладаÑÑÑ ÑÑло вÑдповÑдÑ)
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
console.log(`ÐÑÑимано ${receivedLength} з ${contentLength}`)
}
// ÐÑок 4: обâÑднÑÑмо ÑÑагменÑи в один Uint8Array
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: декодÑÑмо в ÑÑдок
let result = new TextDecoder("utf-8").decode(chunksAll);
// ÐоÑово!
let commits = JSON.parse(result);
alert(commits[0].author.login);
ÐоÑÑнÑмо Ñе кÑок за кÑоком:
-
Ðи виконÑÑмо
fetchÑк зазвиÑай, але замÑÑÑÑ Ñого, Ñоб викликаÑиresponse.json(), оÑÑимÑÑмо доÑÑÑп до поÑÐ¾ÐºÑ Ð·ÑиÑÑваннÑresponse.body.getReader().ÐаÑважÑе, Ñо ми не можемо викоÑиÑÑовÑваÑи обидва ÑÑ Ð¼ÐµÑоди Ð´Ð»Ñ Ð·ÑиÑÑÐ²Ð°Ð½Ð½Ñ Ð¾Ð´Ð½ÑÑÑ Ð²ÑдповÑдÑ: Ñоб оÑÑимаÑи ÑезÑлÑÑаÑ, ÑкоÑиÑÑайÑеÑÑ Ð·ÑиÑÑваÑем
response.json()або меÑодомresponse.body(). -
ÐеÑед зÑиÑÑваннÑм ми можемо визнаÑиÑи Ð¿Ð¾Ð²Ð½Ñ Ð´Ð¾Ð²Ð¶Ð¸Ð½Ñ Ð²ÑдповÑÐ´Ñ Ñз заголовка
Content-Length.ÐÑн може бÑÑи вÑдÑÑÑнÑм Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸ÑÑв мÑж джеÑелами (дивиÑÑ ÑоздÑл Fetch: ÐапиÑи мÑж ÑÑзними джеÑелами), Ñ, взагалÑ-Ñо, ÑÐµÑ Ð½ÑÑно ÑеÑÐ²ÐµÑ Ð½Ðµ зобовâÑзаний його вÑÑановлÑваÑи. Ðле зазвиÑай вÑн пÑиÑÑÑнÑй.
-
ÐикликаÑмо
await reader.read(), до закÑнÑÐµÐ½Ð½Ñ Ð·Ð°Ð²Ð°Ð½ÑаженнÑ.Ðи збиÑаÑмо ÑÑагменÑи вÑдповÑдей Ñ Ð¼Ð°ÑивÑ
chunks. Це важливо, оÑкÑлÑки пÑÑÐ»Ñ Ñого, Ñк вÑдповÑÐ´Ñ Ð±Ñде викоÑиÑÑана, ми не зможемо âпеÑезÑиÑаÑиâ ÑÑ Ð·Ð° допомогоÑresponse.json()або ÑнÑим ÑпоÑобом (ви можеÑе ÑпÑобÑваÑи â бÑде помилка). -
У кÑнÑÑ Ð¼Ð¸ маÑмо
chunksâ маÑив байÑÐ¾Ð²Ð¸Ñ ÑÑагменÑÑвUint8Array. Ðам поÑÑÑбно обâÑднаÑи ÑÑ Ð² Ñдиний ÑезÑлÑÑаÑ. Ðа жалÑ, Ð½ÐµÐ¼Ð°Ñ Ñдиного меÑодÑ, Ñкий би ÑÑ Ð¾Ð±âÑднав, ÑÐ¾Ð¼Ñ Ð´Ð»Ñ ÑÑого Ñ Ð¿ÐµÐ²Ð½Ð¸Ð¹ код:- Ðи ÑÑвоÑÑÑмо
chunksAll = new Uint8Array(receivedLength)â одноÑипний маÑив Ñз Ð·Ð°Ð´Ð°Ð½Ð¾Ñ Ð´Ð¾Ð²Ð¶Ð¸Ð½Ð¾Ñ. - ÐоÑÑм викоÑиÑÑовÑÑмо меÑод
.set(chunk, position), Ñоб ÑкопÑÑваÑи Ñ Ð½Ñого коженchunkодин за одним.
- Ðи ÑÑвоÑÑÑмо
-
ÐаÑмо ÑезÑлÑÑÐ°Ñ Ñ
chunksAll. Ðле Ñе байÑовий маÑив, а не ÑÑдок.Щоб ÑÑвоÑиÑи ÑÑдок, нам поÑÑÑбно ÑнÑеÑпÑеÑÑваÑи ÑÑ Ð±Ð°Ð¹Ñи. ÐбÑдований TextDecoder ÑобиÑÑ Ñаме Ñе. ÐоÑÑм ми можемо пеÑеÑвоÑиÑи ÑÑдок на Ð´Ð°Ð½Ñ Ð·Ð° допомогоÑ
JSON.parse, ÑкÑо Ð½ÐµÐ¾Ð±Ñ Ñдно.Що ÑобиÑи, ÑкÑо нам поÑÑÑбен ÑезÑлÑÑÐ°Ñ Ñ Ð±ÑнаÑÐ½Ð¾Ð¼Ñ Ð²Ð¸Ð³Ð»ÑÐ´Ñ Ð·Ð°Ð¼ÑÑÑÑ ÑÑдка? Це Ñе пÑоÑÑÑÑе. ÐамÑнÑÑÑ ÐºÑоки 4 Ñ 5 ÑÑдком, Ñкий ÑÑвоÑÑÑ
Blobз ÑÑÑÑ ÑÑагменÑÑв:let blob = new Blob(chunks);
ÐапÑикÑнÑÑ Ð¼Ð¸ маÑмо ÑезÑлÑÑÐ°Ñ (Ñк ÑÑдок або Blob, Ñк зÑÑÑно) Ñ Ð²ÑдÑÑÐµÐ¶ÐµÐ½Ð½Ñ Ð¿ÑогÑеÑÑ Ð² пÑоÑеÑÑ.
Ще Ñаз заÑважÑе, Ñо Ñе не Ð´Ð»Ñ Ð¿ÑоÑеÑÑ Ð²Ð¸Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ
на ÑеÑÐ²ÐµÑ (заÑаз Ð½ÐµÐ¼Ð°Ñ Ð·Ð¼Ð¾Ð³Ð¸ викоÑиÑÑовÑваÑи fetch) â лиÑе Ð´Ð»Ñ Ð¿ÑоÑеÑÑ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ
з ÑеÑвеÑа.
ÐÑÑм Ñого, ÑкÑо ÑозмÑÑ Ð·Ð°Ð²Ð°Ð½ÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð½ÐµÐ²Ñдомий, ми Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ Ð¿ÐµÑевÑÑиÑи receivedLength Ñ ÑÐ¸ÐºÐ»Ñ Ñа зÑпиниÑи його, Ñк ÑÑлÑки воно доÑÑгне Ð¿ÐµÐ²Ð½Ð¾Ñ Ð¼ÐµÐ¶Ñ. Щоб chunks не пеÑеповнÑвали памâÑÑÑ.
ÐоменÑаÑÑ
<code>, Ð´Ð»Ñ ÐºÑлÑÐºÐ¾Ñ ÑÑдкÑв â обгоÑнÑÑÑ ÑÑ Ñегом<pre>, Ð´Ð»Ñ Ð¿Ð¾Ð½Ð°Ð´ 10 ÑÑдкÑв â викоÑиÑÑовÑйÑе пÑÑоÑниÑÑ (plnkr, jsbin, codepenâ¦)