aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/reference/statements/for-await...of/index.html
blob: 9c0440c346264fdb9369e82cee2e51984188961b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
---
title: for await...of
slug: Web/JavaScript/Reference/Statements/for-await...of
tags:
  - JavaScript
  - await
  - Інструкція
  - асинхронний
  - перебір
translation_of: Web/JavaScript/Reference/Statements/for-await...of
---
<div>{{jsSidebar("Statements")}}</div>

<p><strong>Інструкція</strong> <strong><code>for await...of</code> </strong>створює цикл, що перебирає як асинхронні ітерабельні об'єкти, так і синхронні ітерабельні об'єкти, в тому числі вбудовані {{jsxref("String")}}, {{jsxref("Array")}}, подібні до масивів об'єкти (наприклад, {{jsxref("Functions/arguments", "arguments")}} чи {{DOMxRef("NodeList")}}), {{jsxref("TypedArray")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, а також визначені користувачем асинхронні/синхронні ітерабельні об'єкти. Вона викликає користувацький хук до ітерацій з командами, що виконуватимуться для значення кожної окремої властивості об'єкта. Як і оператор {{jsxref("Operators/await", "await")}}, інструкція може використовуватись лише всередині {{jsxref("Statements/async_function", "асинхронної функції")}}.</p>

<div class="blockIndicator note">
<p><code>for await...of</code> не працює з асинхронними ітераторами, які не є асинхронними ітерабельними об'єктами.</p>
</div>



<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox">for await (<var>variable</var> of <var>iterable</var>) {
  <var>statement</var>
}
</pre>

<dl>
 <dt><code><var>variable</var></code></dt>
 <dd>На кожній ітерації значення іншої властивості присвоюється змінній <code><var>variable</var></code>. Змінна <code><var>variable</var></code> може бути оголошена через <code>const</code>, <code>let</code> або <code>var</code>.</dd>
 <dt><code><var>iterable</var></code></dt>
 <dd>Об'єкт, чиї ітерабельні властивості перебираються.</dd>
</dl>

<h2 id="Приклади">Приклади</h2>

<h3 id="Перебір_асинхронних_ітерабельних_обєктів">Перебір асинхронних ітерабельних об'єктів</h3>

<p>Ви також можете перебирати об'єкт, який явно реалізує протокол асинхронного ітерабельного об'єкта:</p>

<pre class="brush:js">const asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i &lt; 3) {
          return Promise.resolve({ value: this.i++, done: false });
        }

        return Promise.resolve({ done: true });
      }
    };
  }
};

(async function() {
   for await (let num of asyncIterable) {
     console.log(num);
   }
})();

// 0
// 1
// 2
</pre>

<h3 id="Перебір_асинхронних_генераторів">Перебір асинхронних генераторів</h3>

<p>Оскільки значення, що повертають асинхронні генератори, відповідають протоколу асинхронного ітерабельного об'єкта, їх можна перебирати циклом <code>for await...of</code>.</p>

<pre class="brush: js">async function* asyncGenerator() {
  let i = 0;
  while (i &lt; 3) {
    yield i++;
  }
}

(async function() {
  for await (let num of asyncGenerator()) {
    console.log(num);
  }
})();
// 0
// 1
// 2</pre>

<p>Для більш конкретного прикладу перебору асинхронного генератора за допомогою <code>for await...of</code>, розгляньте перебір даних з API.</p>

<p>Цей приклад спочатку створює асинхронний ітерабельний об'єкт для потоку даних, а далі використовує його, щоб дізнатись розмір відповіді від API.</p>

<pre class="brush: js">async function* streamAsyncIterable(stream) {
  const reader = stream.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        return;
      }
      yield value;
    }
  } finally {
    reader.releaseLock();
  }
}
// Отримує дані з URL та обчислює розмір відповіді за допомогою
// асинхронного генератора.
async function getResponseSize(url) {
  const response = await fetch(url);
  // Міститиме розмір відповіді, у байтах.
  let responseSize = 0;
  // Цикл for-await-of. Асинхронно перебирає кожну частку відповіді.
  for await (const chunk of streamAsyncIterable(response.body)) {
    // Збільшує загальну довжину відповіді.
    responseSize += chunk.length;
  }

  console.log(`Розмір відповіді: ${responseSize} байтів`);
  // очікуваний результат: "Розмір відповіді: 1071472 байтів"
  return responseSize;
}
getResponseSize('https://jsonplaceholder.typicode.com/photos');</pre>

<h3 id="Перебір_синхронних_ітерабельних_обєктів_та_генераторів">Перебір синхронних ітерабельних об'єктів та генераторів</h3>

<p>Цикл <code>for await...of</code> також споживає синхронні ітерабельні об'єкти та генератори. У цьому випадку він внутрішньо чекає на видані значення перед тим, як присвоювати їх керівній змінній циклу.</p>

<pre class="brush: js">function* generator() {
  yield 0;
  yield 1;
  yield Promise.resolve(2);
  yield Promise.resolve(3);
  yield 4;
}

(async function() {
  for await (let num of generator()) {
    console.log(num);
  }
})();
// 0
// 1
// 2
// 3
// 4

// порівняйте з циклом for-of:

for (let numOrPromise of generator()) {
  console.log(numOrPromise);
}
// 0
// 1
// Promise { 2 }
// Promise { 3 }
// 4
</pre>

<div></div>

<div class="blockIndicator note">
<p><strong>Заувага</strong>: остерігайтеся видавати відхилені проміси з синхронного генератора. У цьому випадку <code>for await...of</code> викидає виняток при споживанні відхиленого проміса та НЕ ВИКЛИКАЄ блоки <code>finally</code> всередині цього генератора. Це може бути небажаним, якщо вам треба звільнити певні виділені ресурси за допомогою <code>try/finally</code>.</p>
</div>

<pre class="brush: js">function* generatorWithRejectedPromises() {
  try {
    yield 0;
    yield 1;
    yield Promise.resolve(2);
    yield Promise.reject(3);
    yield 4;
    throw 5;
  } finally {
    console.log('викликано finally')
  }
}

(async function() {
  try {
    for await (let num of generatorWithRejectedPromises()) {
      console.log(num);
    }
  } catch (e) {
    console.log('перехоплено', e)
  }
})();
// 0
// 1
// 2
// перехоплено 3

// порівняйте з циклом for-of:

try {
  for (let numOrPromise of generatorWithRejectedPromises()) {
    console.log(numOrPromise);
  }
} catch (e) {
  console.log('перехоплено', e)
}
// 0
// 1
// Promise { 2 }
// Promise { &lt;rejected&gt; 3 }
// 4
// перехоплено 5
// викликано finally
</pre>

<p>Для того, щоб блоки <code>finally</code> у синхронному генераторі завжди викликались, використовуйте належну форму циклу, <code>for await...of</code> для асинхронних генераторів та <code>for...of</code> для синхронних, та чекайте на видані проміси явно всередині циклу.</p>

<pre class="brush: js">(async function() {
  try {
    for (let numOrPromise of generatorWithRejectedPromises()) {
      console.log(await numOrPromise);
    }
  } catch (e) {
    console.log('перехоплено', e)
  }
})()
// 0
// 1
// 2
// перехоплено 3
// викликано finally</pre>

<h2 id="Специфікації">Специфікації</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Специфікація</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-for-in-and-for-of-statements', 'ECMAScript Language: The for-in, for-of, and for-await-of Statements')}}</td>
  </tr>
 </tbody>
</table>

<h2 id="Сумісність_з_веб-переглядачами">Сумісність з веб-переглядачами</h2>



<p>{{Compat("javascript.statements.for_await_of")}}</p>

<h2 id="Див._також">Див. також</h2>

<ul>
 <li>{{jsxref("Global_Objects/Symbol/asyncIterator", "Symbol.asyncIterator")}}</li>
 <li>{{jsxref("Statements/for...of", "for...of")}}</li>
</ul>