diff options
Diffstat (limited to 'files/ja/web/javascript/reference/statements/for-await...of/index.html')
-rw-r--r-- | files/ja/web/javascript/reference/statements/for-await...of/index.html | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/files/ja/web/javascript/reference/statements/for-await...of/index.html b/files/ja/web/javascript/reference/statements/for-await...of/index.html new file mode 100644 index 0000000000..9d3102375c --- /dev/null +++ b/files/ja/web/javascript/reference/statements/for-await...of/index.html @@ -0,0 +1,255 @@ +--- +title: for await...of +slug: Web/JavaScript/Reference/Statements/for-await...of +tags: + - Iterate + - Iteration + - JavaScript + - Reference + - Statement + - asynchronous + - await + - 文 + - 繰り返し + - 非同期 +translation_of: Web/JavaScript/Reference/Statements/for-await...of +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>for await...of</code> 文</strong>は非同期および同期の<a href="/ja/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol">反復可能オブジェクト</a>を使用して、反復処理を行うループを作成します。たとえば、組込みの {{jsxref("String")}}, {{jsxref("Array")}}, 配列風オブジェクト (例えば {{jsxref("Functions/arguments", "arguments")}}, {{domxref("NodeList")}} など), {{jsxref("TypedArray")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, さらに、ユーザー定義の非同期・同期の反復可能オブジェクトを使用することができます。これはオブジェクトのそれぞれの識別可能なプロパティの値に対して、実行される文を表す独自の反復フックを呼び出します。 {{jsxref("Operators/await", "await")}} 演算子と同様に、この分は{{jsxref("Statements/async_function", "非同期関数", "", 1)}}の中でのみ使用されます。</p> + +<div class="blockIndicator note"> +<p><code>for await...of</code> は非同期の反復可能オブジェクトではない非同期イテレーターでは動作しません。</p> +</div> + +<h2 id="Syntax" name="Syntax">構文</h2> + +<pre class="syntaxbox notranslate">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="Examples" name="Examples">例</h2> + +<h3 id="Iterating_over_async_iterables" name="Iterating_over_async_iterables">非同期の反復可能オブジェクトでの繰り返し処理</h3> + +<p>非同期反復可能プロトコルを明示的に実装しているオブジェクトを反復処理することができます。</p> + +<pre class="brush:js notranslate">const asyncIterable = { + [Symbol.asyncIterator]() { + return { + i: 0, + next() { + if (this.i < 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="Iterating_over_async_generators" name="Iterating_over_async_generators">非同期のジェネレータの反復処理</h3> + +<p>非同期の反復可能プロトコルを実装している非同期ジェネレーターであれば、 <code>for await...of</code> を使用して繰り返し処理を行うことができます。</p> + +<pre class="brush: js notranslate">async function* asyncGenerator() { + let i = 0; + while (i < 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 notranslate">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(`Response Size: ${responseSize} bytes`); + // 期待される出力: "Response Size: 1071472" + return responseSize; +} +getResponseSize('https://jsonplaceholder.typicode.com/photos');</pre> + +<h3 id="Iterating_over_sync_iterables_and_generators" name="Iterating_over_sync_iterables_and_generators">同期の反復可能オブジェクトおよびジェネレーターの反復処理</h3> + +<p><code>for await...of</code> ループは同期の反復可能オブジェクトやジェネレーターで使用することもできます。この場合、内部的にはループの制御変数に代入する前に、値が出力されるのを待ちます。</p> + +<pre class="brush: js notranslate">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 notranslate">function* generatorWithRejectedPromises() { + try { + yield 0; + yield 1; + yield Promise.resolve(2); + yield Promise.reject(3); + yield 4; + throw 5; + } finally { + console.log('called finally') + } +} + +(async function() { + try { + for await (let num of generatorWithRejectedPromises()) { + console.log(num); + } + } catch (e) { + console.log('catched', e) + } +})(); +// 0 +// 1 +// 2 +// catched 3 + +// for-of ループとの比較: + +try { + for (let numOrPromise of generatorWithRejectedPromises()) { + console.log(numOrPromise); + } +} catch (e) { + console.log('catched', e) +} +// 0 +// 1 +// Promise { 2 } +// Promise { <rejected> 3 } +// 4 +// catched 5 +// called finally +</pre> + +<p>同期ジェネレーター関数の <code>finally</code> ブロックが常に呼び出されるようにするには、非同期のジェネレーター関数の場合は <code>for await...of</code> を、同期ジェネレーター関数の場合は <code>for...of</code> を使用し、ループの中で生成されたプロミスを明示的に待つようにしてください。</p> + +<pre class="brush: js notranslate">(async function() { + try { + for (let numOrPromise of generatorWithRejectedPromises()) { + console.log(await numOrPromise); + } + } catch (e) { + console.log('catched', e) + } +})() +// 0 +// 1 +// 2 +// catched 3 +// called finally</pre> + +<h2 id="Specifications" name="Specifications">仕様書</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="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2> + +<div class="hidden">このページの互換性一覧表は構造化データから生成されています。データに協力していただけるのであれば、 <a class="external" href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> をチェックアウトしてプルリクエストを送信してください。</div> + +<p>{{Compat("javascript.statements.for_await_of")}}</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li>{{jsxref("Global_Objects/Symbol/asyncIterator", "Symbol.asyncIterator")}}</li> + <li>{{jsxref("Statements/for...of", "for...of")}}</li> +</ul> |