You signed in with another tab or window.Reload to refresh your session.You signed out in another tab or window.Reload to refresh your session.You switched accounts on another tab or window.Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
The `fetch`method allows to track *download* progress.
Метод `fetch`дозволяє відстежувати хід *завантаження*.
Please note: there's currently no way for`fetch`to track *upload* progress. For that purpose, please use[XMLHttpRequest](info:xmlhttprequest),we'll cover it later.
Будь ласка, зверніть увагу: наразі`fetch`не може відстежувати хід *вивантаження*. Для цієї мети використовуйте[XMLHttpRequest](info:xmlhttprequest),ми розглянемо його пізніше.
To track download progress, we can use`response.body` property. It's a`ReadableStream` --a special object that provides body chunk-by-chunk, as it comes. Readable streams are described in the [Streams API](https://streams.spec.whatwg.org/#rs-class) specification.
Щоб відстежувати хід завантаження, ми можемо використовувати властивість`response.body`. Це`ReadableStream` --спеціальний об’єкт, який надає тіло відповіді фрагментами, в міру надходження. Потоки для зчитування описані в специфікації [Streams API](https://streams.spec.whatwg.org/#rs-class).
Unlike`response.text()`, `response.json()`and other methods, `response.body`gives full control over the reading process, and we can count how much is consumed at any moment.
На відміну від`response.text()`, `response.json()`та інших методів, `response.body`дає повний контроль над процесом зчитування, і ми можемо підрахувати, скільки даних отримано в будь-який момент.
Here's the sketch of code that reads the response from `response.body`:
Ось приклад коду, який зчитує відповідь з `response.body`:
```js
//instead ofresponse.json()and other methods
//замістьresponse.json()та інших методів
const reader = response.body.getReader();
//infinite loop while the body is downloading
//нескінченний цикл, поки тіло відповіді завантажується
while(true) {
// doneis truefor the last chunk
// valueis Uint8Arrayof the chunk bytes
// doneстає trueв останньому фрагменті
// value-- Uint8Arrayз байтів кожного фрагмента
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`Received ${value.length}bytes`)
console.log(`Отримано ${value.length}байт`)
}
```
The result of`await reader.read()`call is an object with two properties:
- **`done`** -- `true` when the reading is complete, otherwise `false`.
- **`value`** --a typed array of bytes: `Uint8Array`.
Результатом виклику`await reader.read()`є об’єкт з двома властивостями:
- **`done`** -- `true`, коли зчитування завершено, інакше -- `false`.
Streams APIalso describes asynchronous iteration over `ReadableStream`with`for await..of` loop, but it's not yet widely supported (see [browser issues](https://github.com/whatwg/streams/issues/778#issuecomment-461341033)),so we use`while` loop.
Streams APIтакож описує асинхронну ітерацію над `ReadableStream`з циклом`for await..of`, але він ще не широко підтримується (дивись [баги браузерів](https://github.com/whatwg/streams/issues/778#issuecomment-461341033)),тому ми використовуємо цикл`while`.
```
We receive response chunks in the loop, until the loading finishes, that is: until`done`becomes `true`.
Ми отримуємо фрагменти відповідей у циклі, поки не закінчиться завантаження, тобто доки`done`не стане `true`.
To log the progress, we just need for every received fragment`value`to add its length to the counter.
Щоб відстежити прогрес, нам просто потрібно для кожного отриманого`value`фрагмента додати його довжину до лічильника.
Here's the full working example that gets the response and logs the progress in console, more explanations to follow:
Ось повний робочий приклад, який отримує відповідь та показує прогрес у консолі, з додатковими поясненнями:
```js run async
//Step 1:start the fetch and obtain a reader
//Крок 1:починаємо завантаження fetch, отримуємо потік для зчитування
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
//Step 4:concatenate chunks into single Uint8Array
//Крок 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;
}
//Step 5:decode into a string
//Крок 5:декодуємо в рядок
let result = new TextDecoder("utf-8").decode(chunksAll);
//We're done!
//Готово!
let commits = JSON.parse(result);
alert(commits[0].author.login);
```
Let's explain that step-by-step:
Пояснімо це крок за кроком:
1.We perform `fetch`as usual, but instead of calling`response.json()`,we obtain a stream reader `response.body.getReader()`.
1.Ми виконуємо `fetch`як зазвичай, але замість того, щоб викликати`response.json()`,отримуємо доступ до потоку зчитування `response.body.getReader()`.
Please note, we can't use both these methods to read the same response: either use a reader or aresponse method to get the result.
2.Prior to reading, we can figure out the full response length from the`Content-Length` header.
Зауважте, що ми не можемо використовувати обидва ці методи для зчитування однієї відповіді: щоб отримати результат, скористайтеся зчитувачем `response.json()` або методом `response.body()`.
2.Перед зчитуванням ми можемо визначити повну довжину відповіді із заголовка`Content-Length`.
It may be absent for cross-origin requests (see chapter <info:fetch-crossorigin>) and, well, technically a server doesn't have to set it. But usually it's at place.
3.Call `await reader.read()` until it's done.
Він може бути відсутнім для запитів між джерелами (дивись розділ <info:fetch-crossorigin>), і, взагалі-то, технічно сервер не зобов’язаний його встановлювати. Але зазвичай він присутній.
3.Викликаємо `await reader.read()`, до закінчення завантаження.
We gather response chunks in the array`chunks`.That's important, because after the response is consumed, we won't be able to "re-read" it using`response.json()`or another way (you can try, there'll be an error).
4.At the end, we have`chunks` --an array of `Uint8Array` byte chunks. We need to join them into a single result. Unfortunately, there's no single method that concatenates those, so there's some code to do that:
1.We create `chunksAll = new Uint8Array(receivedLength)` --a same-typed array with the combined length.
2.Then use`.set(chunk, position)` method to copy each`chunk`one after another in it.
5.We have the result in`chunksAll`.It's a byte array though, not a string.
Ми збираємо фрагменти відповідей у масиві`chunks`.Це важливо, оскільки після того, як відповідь буде використана, ми не зможемо "перезчитати" її за допомогою`response.json()`або іншим способом (ви можете спробувати -- буде помилка).
4.У кінці ми маємо`chunks` --масив байтових фрагментів `Uint8Array`. Нам потрібно об’єднати їх в єдиний результат. На жаль, немає єдиного методу, який би їх об’єднав, тому для цього є певний код:
1.Ми створюємо `chunksAll = new Uint8Array(receivedLength)` --однотипний масив із заданою довжиною.
2.Потім використовуємо метод`.set(chunk, position)`, щоб скопіювати у нього кожен`chunk`один за одним.
5.Маємо результат у`chunksAll`.Але це байтовий масив, а не рядок.
To create a string, we need to interpret these bytes. The built-in[TextDecoder](info:text-decoder)does exactly that. Then we can`JSON.parse` it, if necessary.
Щоб створити рядок, нам потрібно інтерпретувати ці байти. Вбудований[TextDecoder](info:text-decoder)робить саме це. Потім ми можемо перетворити рядок на дані за допомогою`JSON.parse`, якщо необхідно.
What if we need binary content instead of a string? That's even simpler. Replace steps 4and 5with a single line that creates a`Blob`from all chunks:
Що робити, якщо нам потрібен результат у бінарному вигляді замість рядка? Це ще простіше. Замініть кроки 4і 5рядком, який створює`Blob`з усіх фрагментів:
```js
let blob = new Blob(chunks);
```
At the end we have the result (as a string or a blob, whatever is convenient), and progress-tracking in the process.
Наприкінці ми маємо результат (як рядок або `Blob`, як зручно) і відстеження прогресу в процесі.
Once again, please note, that's not for *upload* progress (no way now with `fetch`), only for *download* progress.
Ще раз зауважте, що це не для процесу *вивантаження* даних на сервер (зараз немає змоги використовувати `fetch`) -- лише для процесу *завантаження* даних з сервера.
Also, if the size is unknown, we should check `receivedLength`in the loop and break it once it reaches a certain limit. So that the`chunks`won't overflow the memory.
Крім того, якщо розмір завантаження невідомий, ми повинні перевірити `receivedLength`у циклі та зупинити його, як тільки воно досягне певної межі. Щоб`chunks`не переповнювали пам’ять.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.