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
The`fetch`method allows to track *download* progress.
4
+
متد`fetch`به ما اجازه میدهد پیشرفت *دانلود* را دنبال کنیم.
5
5
6
-
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.
6
+
لطفاً توجه کنید: در حال حاضر هیچ راهی وجود ندارد که `fetch`بتواند پیشرفت *آپلود* را ردیابی کند. برای این کار باید از[XMLHttpRequest](info:xmlhttprequest) استفاده کنید که بعداً بررسی خواهد شد.
7
7
8
-
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.
8
+
برای دنبالکردن پیشرفت دانلود، میتوانیم از ویژگی`response.body`استفاده کنیم. این یک`ReadableStream`است -- یک شیء خاص که بدنه را به صورت تکهتکه (chunk-by-chunk) و همزمان با دریافت فراهم میکند. جریانهای قابل خواندن در [Streams API](https://streams.spec.whatwg.org/#rs-class)توضیح داده شدهاند.
9
9
10
-
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.
10
+
برخلاف`response.text()`،`response.json()`و سایر متدها، ویژگی `response.body`کنترل کامل روی فرایند خواندن میدهد و میتوانیم در هر لحظه مقدار دادهی مصرفشده را اندازهگیری کنیم.
11
11
12
-
Here's the sketch of code that reads the response from`response.body`:
12
+
در ادامه اسکلت کدی را میبینید که پاسخ را از`response.body` میخواند:
13
13
14
14
```js
15
-
//instead of response.json() and other methods
15
+
//بهجای response.json() و سایر متدها
16
16
constreader=response.body.getReader();
17
17
18
-
//infinite loop while the body is downloading
18
+
//حلقه بینهایت تا زمانی که بدنه در حال دانلود است
19
19
while(true) {
20
-
// done is true for the last chunk
21
-
// value is Uint8Array of the chunk bytes
20
+
// done برای آخرین chunk برابر true میشود
21
+
// value یک Uint8Array از بایتهای chunk است
22
22
const {done, value} =awaitreader.read();
23
23
24
24
if (done) {
@@ -29,32 +29,34 @@ while(true) {
29
29
}
30
30
```
31
31
32
-
The result of `await reader.read()` call is an object with two properties:
33
-
-**`done`** -- `true` when the reading is complete, otherwise `false`.
34
-
-**`value`** -- a typed array of bytes: `Uint8Array`.
32
+
نتیجهی فراخوانی `await reader.read()` یک شیء با دو ویژگی است:
33
+
34
+
* ویژگی **`done`** -- زمانی `true` میشود که خواندن کامل شده باشد، در غیر این صورت `false` است.
35
+
* ویژگی **`value`** -- یک آرایه تایپشده از بایتها: `Uint8Array`.
35
36
36
37
```smart
37
-
Streams API also 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.
38
+
توجه: Streams API همچنین پیمایش ناهمزمان (`async iteration`) روی `ReadableStream` را با حلقهی `for await..of` تعریف میکند، اما هنوز به طور گسترده پشتیبانی نمیشود (به [مشکلات مرورگرها](https://github.com/whatwg/streams/issues/778#issuecomment-461341033) مراجعه کنید)، بنابراین از حلقهی `while` استفاده میکنیم.
38
39
```
39
40
40
-
We receive response chunks in the loop, until the loading finishes, that is: until `done`becomes`true`.
41
+
ما در حلقه، تکههای پاسخ را دریافت میکنیم تا زمانی که بارگذاری تمام شود؛ یعنی تا زمانی که `done`برابر`true` شود.
41
42
42
-
To log the progress, we just need for every received fragment `value` to add its length to the counter.
43
+
برای ثبت پیشرفت، کافی است در هر بار دریافت قطعهی `value`، طول آن را به شمارنده اضافه کنیم.
43
44
44
-
Here's the full working example that gets the response and logs the progress in console, more explanations to follow:
45
+
در ادامه یک مثال کامل داریم که پاسخ را دریافت میکند و پیشرفت را در کنسول لاگ میکند. توضیحات بیشتر بعد از آن آمده است:
45
46
46
47
```js run async
47
-
//Step 1: start the fetch and obtain a reader
48
+
//مرحله 1: شروع fetch و گرفتن reader
48
49
let response =awaitfetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
let receivedLength =0; // received that many bytes at the moment
57
-
let chunks = []; // array of received binary chunks (comprises the body)
56
+
// مرحله 3: خواندن داده
57
+
let receivedLength =0; // تا این لحظه این مقدار بایت دریافت شده
58
+
let chunks = []; // آرایهای از تکههای باینری دریافتشده (بدنه)
59
+
58
60
while(true) {
59
61
const {done, value} =awaitreader.read();
60
62
@@ -68,47 +70,53 @@ while(true) {
68
70
console.log(`Received ${receivedLength} of ${contentLength}`)
69
71
}
70
72
71
-
//Step 4: concatenate chunks into single Uint8Array
72
-
let chunksAll =newUint8Array(receivedLength); // (4.1)
73
+
//مرحله 4: اتصال chunkها به یک Uint8Array واحد
74
+
let chunksAll =newUint8Array(receivedLength); // (مرحله 4.1)
73
75
let position =0;
74
76
for(let chunk of chunks) {
75
-
chunksAll.set(chunk, position); // (4.2)
76
-
position +=chunk.length;
77
+
chunksAll.set(chunk, position); // (مرحله 4.2)
78
+
position +=chunk.length;
77
79
}
78
80
79
-
//Step 5: decode into a string
81
+
//مرحله 5: تبدیل به رشته
80
82
let result =newTextDecoder("utf-8").decode(chunksAll);
81
83
82
-
//We're done!
84
+
//کار تمام شد!
83
85
let commits =JSON.parse(result);
84
86
alert(commits[0].author.login);
85
87
```
86
88
87
-
Let's explain that step-by-step:
89
+
بیایید مرحله به مرحله توضیح بدهیم:
90
+
91
+
1. ما مانند حالت عادی `fetch` انجام میدهیم، اما به جای `response.json()`، یک stream reader میگیریم: `response.body.getReader()`.
92
+
93
+
توجه کنید که نمیتوان همزمان از هر دو روش برای خواندن یک پاسخ استفاده کرد: یا باید از reader استفاده کنیم یا از متدهای آمادهی response.
94
+
95
+
2. قبل از خواندن، میتوانیم از هدر `Content-Length` طول کل پاسخ را به دست آوریم.
96
+
97
+
این مقدار ممکن است در درخواستهای cross-origin وجود نداشته باشد (به فصل <info:fetch-crossorigin> مراجعه کنید) و در عمل هم سرور مجبور به ارسال آن نیست. اما معمولاً وجود دارد.
98
+
99
+
3. تابع `await reader.read()` را تا زمانی که تمام شود اجرا میکنیم.
100
+
101
+
ما تکههای پاسخ را در آرایهی `chunks` جمع میکنیم. این مهم است چون بعد از مصرف شدن پاسخ، دیگر نمیتوان آن را دوباره با `response.json()` یا روشهای مشابه خواند (اگر امتحان کنید خطا خواهید گرفت).
88
102
89
-
1. We perform `fetch` as usual, but instead of calling `response.json()`, we obtain a stream reader `response.body.getReader()`.
103
+
4. در پایان، ما `chunks` را داریم -- آرایهای از قطعات بایت `Uint8Array`. باید آنها را به یک خروجی واحد تبدیل کنیم. متأسفانه متد مستقیمی برای اتصال آنها وجود ندارد، بنابراین این کار را دستی انجام میدهیم:
90
104
91
-
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.
92
-
2.Prior to reading, we can figure out the full response length from the `Content-Length` header.
105
+
1. یک `Uint8Array` جدید با طول کل ایجاد میکنیم: `chunksAll = new Uint8Array(receivedLength)`
106
+
2.سپس با `.set(chunk, position)` هر قطعه را پشت سر هم داخل آن کپی میکنیم.
93
107
94
-
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.
95
-
3. Call `await reader.read()` until it's done.
108
+
5. در نهایت دادهی نهایی در `chunksAll` قرار دارد، اما هنوز رشته نیست.
96
109
97
-
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).
98
-
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:
99
-
1. We create `chunksAll = new Uint8Array(receivedLength)` -- a same-typed array with the combined length.
100
-
2. Then use `.set(chunk, position)` method to copy each `chunk` one after another in it.
101
-
5. We have the result in `chunksAll`. It's a byte array though, not a string.
110
+
برای تبدیل به رشته، باید این بایتها را تفسیر کنیم. کلاس داخلی [TextDecoder](info:text-decoder) دقیقاً همین کار را انجام میدهد. سپس در صورت نیاز میتوانیم آن را با `JSON.parse` تبدیل کنیم.
102
111
103
-
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.
112
+
اگر به جای رشته دادهی باینری بخواهیم، کار سادهتر است: کافی است مراحل 4 و 5 را با یک خط جایگزین کنیم:
104
113
105
-
What if we need binary content instead of a string? That's even simpler. Replace steps 4 and 5 with a single line that creates a `Blob` from all chunks:
106
-
```js
107
-
let blob =newBlob(chunks);
108
-
```
114
+
```js
115
+
let blob =newBlob(chunks);
116
+
```
109
117
110
-
At the end we have the result (as a string or a blob, whatever is convenient), and progress-tracking in the process.
118
+
در نهایت ما نتیجه را (به صورت رشته یا Blob) داریم و همزمان در طول فرایند، پیشرفت دانلود را هم دنبال میکنیم.
111
119
112
-
Once again, please note, that's not for *upload* progress (no way now with `fetch`), only for *download* progress.
120
+
دوباره توجه کنید: این روش برای *پیشرفت آپلود* نیست (فعلاً با `fetch` ممکن نیست)، فقط برای *پیشرفت دانلود* است.
113
121
114
-
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.
122
+
همچنین اگر اندازهی داده مشخص نباشد، باید در حلقه مقدار `receivedLength`را بررسی کنیم و اگر از یک حدی بیشتر شد، حلقه را متوقف کنیم تا آرایهی `chunks`باعث مصرف بیش از حد حافظه نشود.
0 commit comments