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
254
255
256
257
258
259
|
---
title: 非同期関数
slug: Web/JavaScript/Reference/Statements/async_function
tags:
- Example
- Function
- JavaScript
- Language feature
- Statement
- 文
- 言語機能
- 関数
translation_of: Web/JavaScript/Reference/Statements/async_function
---
<div>{{jsSidebar("Statements")}}</div>
<p><span class="seoSummary"><code><strong>async function</strong></code> 宣言は、 <strong>非同期関数</strong> — {{jsxref("Global_Objects/AsyncFunction","AsyncFunction")}} オブジェクトである関数を定義します。非同期関数は<a href="/ja/docs/Web/JavaScript/EventLoop">イベントループ</a>を介して他のコードとは別に実行され、結果として暗黙の {{jsxref("Promise")}} を返します。ただし、非同期関数を使用したコードの構文および構造は、通常の同期関数と似たものになります。</span></p>
<div class="noinclude">
<p>{{jsxref("Operators/async_function", "async function 式", "", 1)}} を使用して非同期関数を定義することもできます。</p>
</div>
<div>{{EmbedInteractiveExample("pages/js/statement-async.html", "taller")}}</div>
<div class="hidden">このインタラクティブデモのソースは GitHub のリポジトリに格納されています。インタラクティブデモプロジェクトに協力したい場合は、 <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> をクローンしてプルリクエストを送ってください。</div>
<h2 id="Syntax" name="Syntax">構文</h2>
<pre class="syntaxbox notranslate">async function <var>name</var>([<var>param</var>[, <var>param</var>[, ...<var>param</var>]]]) {
<var>statements</var>
}
</pre>
<h3 id="Parameters" name="Parameters">引数</h3>
<dl>
<dt><code><var>name</var></code></dt>
<dd>関数名。</dd>
<dt><code><var>param</var></code></dt>
<dd>関数に渡す引数名。</dd>
<dt><code><var>statements</var></code></dt>
<dd>関数の本体を構成する文。</dd>
</dl>
<h3 id="Return_value" name="Return_value">返値</h3>
<p>{{jsxref("Promise")}} で、非同期関数から返される値で解決するか、または非同期関数内の捕捉されなかった例外で拒否します。</p>
<h2 id="Description" name="Description">解説</h2>
<p>非同期関数は、 {{jsxref("Operators/await", "await")}} 式を含むことができます。これは非同期関数の実行を一時停止し、 <code>Promise</code> の解決を待ちます。そして非同期関数の実行を再開し、解決された値を返します。</p>
<p><strong>キーワード <code>await</code> は、非同期関数の中でのみ有効です。</strong>非同期関数の外で使用した場合は {{jsxref("SyntaxError")}} となります。</p>
<p>非同期関数が一時停止している間、呼び出し側の関数は実行が続きます (非同期関数から返される暗黙の Promise を受け取ります)。</p>
<div class="note">
<p><code>async</code>/<code>await</code> の目的は、 Promise を同期的に使用する動作を簡素化し、 <code>Promise</code> のグループに対して何らかの動作を実行することです。 <code>Promise</code> が構造化コールバックに似ているのと同様に、 <code>async</code>/<code>await</code> はジェネレーターと Promise を組み合わせたものに似ています。</p>
</div>
<h2 id="Examples" name="Examples">例</h2>
<h3 id="Simple_example" name="Simple_example">シンプルな例</h3>
<pre class="brush: js notranslate">function resolveAfter2Seconds() {
console.log("starting slow promise")
return new Promise(resolve => {
setTimeout(function() {
resolve("slow")
console.log("slow promise is done")
}, 2000)
})
}
function resolveAfter1Second() {
console.log("starting fast promise")
return new Promise(resolve => {
setTimeout(function() {
resolve("fast")
console.log("fast promise is done")
}, 1000)
})
}
async function sequentialStart() {
console.log('==SEQUENTIAL START==')
// 1. ここは即時実行される
const slow = await resolveAfter2Seconds()
console.log(slow) // 2. ここは 1. の2秒後に実行される
const fast = await resolveAfter1Second()
console.log(fast) // 3. ここは 1. の3秒後に実行される
}
async function concurrentStart() {
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds() // 即時実行
const fast = resolveAfter1Second() // 即時実行
// 1. ここは即時実行される
console.log(await slow) // 2. ここは 1. の2秒後に実行される
console.log(await fast) // 3. ここは 1. の2秒後(2.の直後)に実行される
}
function concurrentPromise() {
console.log('==CONCURRENT START with Promise.all==')
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]) // slow
console.log(messages[1]) // fast
})
}
async function parallel() {
console.log('==PARALLEL with await Promise.all==')
// 2つの jobs を並列に実行し両方が完了するのを待つ
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
])
}
// この関数はエラーハンドリングをしていません。後述の注意書きを参照してください。
function parallelPromise() {
console.log('==PARALLEL with Promise.then==')
resolveAfter2Seconds().then((message)=>console.log(message))
resolveAfter1Second().then((message)=>console.log(message))
}
sequentialStart() // 2秒後に "slow" をログ出力し、その1秒後に "fast" をログ出力する
// 見やすくするため setTimeout で直前の処理が終わるのを待つ
setTimeout(concurrentStart, 4000) // 2秒後に "slow" と "fast" をログ出力する
// 直前の処理を待つ
setTimeout(concurrentPromise, 7000) // concurrentStart と同様
// 直前の処理を待つ
setTimeout(parallel, 10000) // 本当に並列処理となるため1秒後に "fast" とログ出力し、その1秒後に "slow" とログ出力する
// 直前の処理を待つ
setTimeout(parallelPromise, 13000) // parallel と同様
</pre>
<h4 id="await_and_parallelism" name="await_and_parallelism">await と並列性</h4>
<p><code>sequentialStart</code> では、最初の <code>await</code> のために実行が 2 秒間待機し、 2 つ目の <code>await</code> のためにさらに 1 秒間待機します。 2 つ目のタイマーは最初のタイマーが起動している間は作成されません。コードは 3 秒後に終了します。</p>
<p><code>concurrentStart</code> では、両方のタイマーが作成され、両方とも <code>await</code> される、すなわち待機させられます。タイマーは同時に実行されているため、 3 秒後ではなく 2 秒後に、すなわち最も遅いタイマーにあわせて終了します。<br>
しかし、 <code>await</code> の呼び出しは依然として逐次処理であり、これは 2 つ目の <code>await</code> が 1 つ目の終了まで待つことを意味します。このケースでは、最も速いタイマーが最も遅いタイマーのあとに処理されることになります。</p>
<p>もし複数の処理を完全に並列に実行したい場合は、上記コード中の <code>parallel</code> のように <code>await Promise.all([job1(), job2()])</code> を使わなければなりません。</p>
<div class="warning">
<h4 id="asyncawait_vs_Promise.then_and_error_handling" name="asyncawait_vs_Promise.then_and_error_handling">async/await と Promise.then およびエラー処理</h4>
<p>多くの非同期関数は Promise を用いて通常の関数として書くことができます。しかし <code>async</code> 関数はエラー処理において少し簡単です。</p>
<p><code>concurrentStart</code>と<code>concurrentPromise</code>のどちらも関数としては同値です。</p>
<ul>
<li><code>concurrentStart</code> では、 <code>await</code> されたいずれかの関数呼び出しが失敗すれば、例外は自動的にキャッチされ、非同期関数の実行が中断され、暗黙的に返される Promise を経由してエラーが呼び出し元へ伝えられます。</li>
<li>同じことが Promise の場合にも起こり、関数は、関数の完了をとらえて戻ってくる <code>Promise</code> の面倒を見なければなりません。これは <code>concurrentPromise</code> では <code>Promise.all([]).then()</code> が返す Promise を <code>return</code> することを意味します。実は、この例の前のバージョンはこれをやり忘れていました!</li>
</ul>
<p>しかしながら非同期関数も誤ってエラーを飲み込んでしまうことがあります。</p>
<p>上記の <code>parallel</code> という非同期関数を例にしてみましょう。もしこれが <code>Promise.all([])</code> 呼び出しの結果を <code>await</code> (もしくは <code>return</code>) しなければ、任意のエラーは伝わりません。</p>
<p><code>parallelPromise</code> の例は簡潔に見えるものの、エラーをまったくハンドルしていません!同じことをするには、やはり <code>return Promise.all[()]</code> が必要になります。</p>
</div>
<h3 id="Rewriting_a_promise_chain_with_an_async_function" name="Rewriting_a_promise_chain_with_an_async_function">promise チェーンをasync function で 書き換える</h3>
<p>Promise を返す API は Promise チェーンで解決され、関数を複数の部品に分割できます。次のコードを想定してください。</p>
<pre class="brush: js notranslate">function getProcessedData(url) {
return downloadData(url) // returns a promise
.catch(e => {
return downloadFallbackData(url) // returns a promise
})
.then(v => {
return processDataInWorker(v) // returns a promise
})
}
</pre>
<p>次のように 1 つの <code>async</code> 関数に書き直すことができます。</p>
<pre class="brush: js notranslate">async function getProcessedData(url) {
let v
try {
v = await downloadData(url)
} catch(e) {
v = await downloadFallbackData(url)
}
return processDataInWorker(v)
}
</pre>
<p>上記の例では、 <code>return</code> ステートメント上に <code>await</code> ステートメントがないことに注目してください。なぜなら、<code>async function</code> の返値は暗黙的に {{jsxref("Promise.resolve")}} でラップされているからです。</p>
<div class="blockIndicator note">
<h4 id="return_await_promiseValue_vs._return_promiseValue" name="return_await_promiseValue_vs._return_promiseValue">return await promiseValue と return promiseValue</h4>
<p>返値が {{jsxref("Promise.resolve")}} で暗黙にラッピングされるとはいえ、 <code>return await promiseValue</code> が <code>return promiseValue</code> と機能的に等価である訳ではありません。</p>
<p>上記のコードを以下のように書き直したと想像してください。これは <code>processDataInWorker</code> がエラーで拒否した場合に <code>null</code> を返します。</p>
<pre class="brush: js notranslate">async function getProcessedData(url) {
let v
try {
v = await downloadData(url)
} catch(e) {
v = await downloadFallbackData(url)
}
try {
return await processDataInWorker(v) // Note the `return await` vs. just `return`
} catch (e) {
return null
}
}
</pre>
<p><code>return processDataInWorker(v)</code> と記述すると、 <code>processDataInWorker(v)</code> が拒否した場合に <code>null</code> に解決されるのではなく、関数が返した {{jsxref("Promise")}} が拒否されてしまいます。</p>
<p>これは、 <code>return foo;</code> と <code>return await foo;</code> の微妙な違いを強調しています。 - <code>return foo</code> はすぐに <code>foo</code> を返し、 <code>foo</code> が拒否する Promise であっても例外を発生させません。 <code>return await foo</code> は、それが Promise であれば <code>foo</code> が解決するか拒否するかを待ち、拒否した場合は<strong>返す前</strong>に例外を発生させます。</p>
</div>
<h2 id="Specifications" name="Specifications">仕様書</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">仕様書</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ESDraft', '#sec-async-function-definitions', 'async function')}}</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2>
<div>
<p>{{Compat("javascript.statements.async_function")}}</p>
</div>
<h2 id="See_also" name="See_also">関連情報</h2>
<ul>
<li>{{jsxref("Operators/async_function", "async function expression")}}</li>
<li>{{jsxref("AsyncFunction")}} オブジェクト</li>
<li>{{jsxref("Operators/await", "await")}}</li>
<li><a href="http://innolitics.com/10x/javascript-decorators-for-promise-returning-functions/">"innolitics.com" の "Decorating Async Javascript Functions"</a></li>
</ul>
|