Skip to content

Commit 7eb6e91

Browse files
Merge pull request #197 from alfiya-udc/master
Fetch: Download progress
2 parents a74c17f + c9b0fff commit 7eb6e91

File tree

1 file changed

+39
-39
lines changed

1 file changed

+39
-39
lines changed
Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
11

2-
# Fetch: Download progress
2+
# Fetch: ход загрузки
33

4-
`Fetch` allows to track download progress, but not upload progress.
4+
`Fetch` позволяет отслеживать процесс получения данных.
55

6-
Please note: there's currently no way for fetch to track upload progress. For that purpose, please use [XMLHttpRequest](info:xmlhttprequest).
6+
Заметим, на данный момент в `fetch` нет способа отследить прогресс отправки данных. Для этого используйте [XMLHttpRequest](info:xmlhttprequest).
77

8-
To track download progress, we can use `response.body` property. It's a "readable stream" -- a special object that provides body chunk-by-chunk, as it comes, so we can see how much is available at the moment.
8+
Если мы хотим отследить ход загрузки данных с сервера, можно использовать свойство `response.body`. Это так называемый "поток для чтения" (англ. `readable stream`) -- особый объект, который предоставляет тело ответа по частям, по мере поступления, так что мы можем увидеть, сколько уже получено.
99

10-
Here's the sketch of code that uses it to read response:
10+
Вот пример кода, который использует этот объект для чтения ответа:
1111

1212
```js
13-
// instead of response.json() and other methods
13+
// вместо response.json() и других методов
1414
const reader = response.body.getReader();
1515

16-
// infinite loop while the body is downloading
16+
// бесконечный цикл, пока идёт загрузка
1717
while(true) {
18-
// done is true for the last chunk
19-
// value is Uint8Array of the chunk bytes
18+
// done становится true в последнем фрагменте
19+
// value - Uint8Array из байтов каждого фрагмента
2020
const {done, value} = await reader.read();
2121

2222
if (done) {
2323
break;
2424
}
2525

26-
console.log(`Received ${value.length} bytes`)
26+
console.log(`Получено ${value.length} байт`)
2727
}
2828
```
2929

30-
So, we loop, while `await reader.read()` returns response chunks.
30+
Таким образом, цикл идёт, пока `await reader.read()` возвращает в ответе данные по частям.
3131

32-
A chunk has two properties:
33-
- **`done`** -- true when the reading is complete.
34-
- **`value`** -- a typed array of bytes: `Uint8Array`.
32+
У возвращаемого фрагмента (англ. `chunk`) есть два свойства:
33+
- **`done`** -- `true`, когда чтение закончено.
34+
- **`value`** -- типизированный массив байтов: `Uint8Array`.
3535

36-
To log the progress, we just need to count chunks.
36+
Чтобы пошагово отследить процесс, нам нужно всего лишь посчитать получившиеся фрагменты.
3737

38-
Here's the full code to get response and log the progress, more explanations follow:
38+
Вот полный код, где в процессе получения ответа от сервера мы фиксируем, сколько данных пришло из каждой части.
3939

4040
```js run async
41-
// Step 1: start the fetch and obtain a reader
41+
// Шаг 1: начинаем обработку с помощью fetch и достаём ссылку на поток для чтения
4242
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
4343

4444
const reader = response.body.getReader();
4545

46-
// Step 2: get total length
46+
// Шаг 2: получаем длину контента
4747
const contentLength = +response.headers.get('Content-Length');
4848

49-
// Step 3: read the data
50-
let receivedLength = 0; // length at the moment
51-
let chunks = []; // array of received binary chunks (comprises the body)
49+
// Шаг 3: считываем данные:
50+
let receivedLength = 0; // длину на данный момент
51+
let chunks = []; // массив полученных двоичных фрагментов (в нём будет тело ответа)
5252
while(true) {
5353
const {done, value} = await reader.read();
5454

@@ -59,46 +59,46 @@ while(true) {
5959
chunks.push(value);
6060
receivedLength += value.length;
6161

62-
console.log(`Received ${receivedLength} of ${contentLength}`)
62+
console.log(`Получено ${receivedLength} из ${contentLength}`)
6363
}
6464

65-
// Step 4: concatenate chunks into single Uint8Array
65+
// Шаг 4: соединим фрагменты в общий типизированный массив Uint8Array
6666
let chunksAll = new Uint8Array(receivedLength); // (4.1)
6767
let position = 0;
6868
for(let chunk of chunks) {
6969
chunksAll.set(chunk, position); // (4.2)
7070
position += chunk.length;
7171
}
7272

73-
// Step 5: decode into a string
73+
// Шаг 5: декодируем Uint8Array обратно в строку
7474
let result = new TextDecoder("utf-8").decode(chunksAll);
7575

76-
// We're done!
76+
// Готово!
7777
let commits = JSON.parse(result);
7878
alert(commits[0].author.login);
7979
```
8080

81-
Let's explain that step-by-step:
81+
Разберёмся, что здесь произошло:
8282

83-
1. We perform `fetch` as usual, but instead of calling `response.json()`, we obtain a stream reader `response.body.getReader()`.
83+
1. Мы обращаемся к `fetch` как обычно, но вместо вызова `response.json()` мы получаем доступ к потоку чтения `response.body.getReader()`.
8484

85-
Please note, we can't use both these methods to read the same response. Either use a reader or a response method to get the result.
86-
2. Prior to reading, we can figure out the full response length from the `Content-Length` header.
85+
Обратите внимание, что мы не можем использовать одновременно оба эти метода для одного и того же ответа. Используйте либо обычный метод `response.json()`, либо чтение потока `response.body`.
86+
2. Ещё до чтения потока мы можем вычислить полную длину ответа из заголовка `Content-Length`.
8787

88-
It may be absent for cross-domain requests (see chapter <info:fetch-crossorigin>) and, well, technically a server doesn't have to set it. But usually it's at place.
89-
3. Call `await reader.read()` until it's done.
88+
Она может отсутствовать в кросс-доменных запросах (подробнее в разделе <info:fetch-crossorigin>) и, в общем-то, серверу необязательно её устанавливать. Тем не менее, обычно длина указана.
89+
3. Вызываем `await reader.read()` до окончания загрузки.
9090

91-
We gather response `chunks` in the array. 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).
92-
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:
93-
1. We create `new Uint8Array(receivedLength)` -- a same-typed array with the combined length.
94-
2. Then use `.set(chunk, position)` method to copy each `chunk` one after another in the resulting array.
95-
5. We have the result in `chunksAll`. It's a byte array though, not a string.
91+
Всё, что получили, мы складываем по "кусочкам" в массив. Это важно, потому что после того, как ответ получен, мы уже не сможем "перечитать" его, используя `response.json()` или любой другой способ (попробуйте - будет ошибка).
92+
4. В самом конце у нас типизированный массив -- `Uint8Array`. В нём находятся фрагменты данных. Нам нужно их склеить, чтобы получить строку. К сожалению, для этого нет специального метода, но можно сделать, например, так:
93+
1. Создаём `new Uint8Array(receivedLength)` -- массив того же типа заданной длины.
94+
2. Используем `.set(chunk, position)` метод для копирования каждого фрагмента друг за другом в массив результатов.
95+
5. Наш результат теперь хранится в `chunksAll`. Это не строка, а байтовый массив.
9696

97-
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.
97+
Чтобы получить именно строку, надо декодировать байты. Встроенный метод [TextDecoder](info:text-decoder) как раз этим и занимается. Потом мы можем распарсить её с помощью `JSON.parse`.
9898

99-
What if we need binary content instead of JSON? That's even simpler. Instead of steps 4 and 5, we could make a blob of all chunks:
99+
Что если результат нам нужен в бинарном виде, а не в JSON-формате? Это ещё проще. Вместо шагов 4 и 5, мы создаём объект `Blob`:
100100
```js
101101
let blob = new Blob(chunks);
102102
```
103103

104-
Once again, please note, that's not for upload progress (no way now), only for download progress.
104+
На всякий случай повторимся, что здесь мы рассмотрели, как отслеживать процесс получения данных с сервера, а не их отправки на сервер. Как отследить отправку `fetch` - пока нет способа.

0 commit comments

Comments
 (0)