aboutsummaryrefslogtreecommitdiff
path: root/files/ja/web/javascript/guide/using_promises/index.html
blob: df6cd820bc19136033b8fe3073107ceda7817ae8 (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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
---
title: Promiseを使う
slug: Web/JavaScript/Guide/Using_promises
tags:
  - Guide
  - Intermediate
  - JavaScript
  - Promise
  - Promises
  - asynchronous
  - 'l10n:priority'
translation_of: Web/JavaScript/Guide/Using_promises
---
<div>{{jsSidebar("JavaScript Guide")}}</div>

<p class="summary">{{jsxref("Promise")}} は非同期処理の最終的な完了もしくは失敗を表すオブジェクトです。多くの人々は既存の用意された Promise を使うことになるため、このガイドでは、Promise の作成方法の前に、関数が返す Promise の使い方から説明します。</p>

<p>本質的に、Promise はコールバックを関数に渡すかわりに、関数が返したオブジェクトに対してコールバックを登録するようにする、というものです。</p>

<p>例えば <code>createAudioFileAsync()</code> という非同期に音声ファイルを生成する関数を考えましょう。この関数はコンフィグオブジェクトと 2 つのコールバック関数を受け取り、片方のコールバックは音声ファイルが無事作成されたときに呼び出され、もう一つはエラーが発生したときに呼び出されます。</p>

<p>以下のコードは <code>createAudioFileAsync()</code> を使用したものです。</p>

<pre class="brush: js notranslate">function successCallback(result) {
  console.log("Audio file ready at URL: " + result);
}

function failureCallback(error) {
  console.log("Error generating audio file: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);</pre>

<p>最近では関数は Promise を返し、代わりにその Promise にコールバックを登録することができます。</p>

<p>もし <code>createAudioFileAsync()</code> が Promise を返すように書き換えられたとすれば、以下のようにシンプルに使用することができます。</p>

<pre class="brush: js notranslate">createAudioFileAsync(audioSettings).then(successCallback, failureCallback);</pre>

<p>これは以下のコードの短縮形です。</p>

<pre class="brush: js notranslate">const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);</pre>

<p>これを<em>非同期関数呼び出し(asynchronnous function call)</em>と呼びます。この記述方法にはいくつか利点があるので、順に説明します。</p>

<h2 id="Guarantees" name="Guarantees">保証</h2>

<p>旧来のコールバック渡しとは異なり、Promise では以下が保証されています。</p>

<ul>
 <li>現在の JavaScript イベントループの<a href="/ja/docs/Web/JavaScript/EventLoop#Run-to-completion">実行完了</a>より前には、コールバックが決して呼び出されない。</li>
 <li>非同期処理が完了もしくは失敗した後に <code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> により登録されたコールバックでも、上記のように呼び出される。</li>
 <li><code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> を何回も呼び出して複数のコールバックを追加してもよく、それぞれのコールバックは追加順に独立して実行される。</li>
</ul>

<p>とはいえ、最もすぐわかる Promise の利点は <strong>Promise チェーン</strong>でしょう。</p>

<h2 id="Chaining" name="Chaining">Promise チェーン</h2>

<p>一般的なニーズとしては、複数の非同期処理を順番に実行し、前の処理が完了してからその結果を次の処理で使うというものがあります。これは <strong>Promise チェーン</strong>を作成することで行えます。</p>

<p>さあ魔法の時間です。<code>then()</code> 関数は元の Promise とは別の<strong>新しい Promise</strong> を返します。</p>

<pre class="brush: js notranslate">const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
</pre>

<p>もしくは、以下のように書いても構いません。</p>

<pre class="brush: js notranslate">const promise2 = doSomething().then(successCallback, failureCallback);
</pre>

<p>2 つ目の Promise は <code>doSomething()</code> の完了を表すだけではなく、渡した <code>successCallback</code> もしくは <code>failureCallback</code> の完了も表し、これらのコールバックは Promise を返すまた別の非同期関数であっても構いません。その場合、<code>promise2</code> に追加されたコールバックはいずれも Promise のキューにおいて、<code>successCallback</code> または <code>failureCallback</code> が返す Promise の後ろに追加されます。</p>

<p>基本的に、それぞれの Promise はチェーン(連鎖)上の各非同期処理の完了を表します。</p>

<p>昔は、複数の非同期処理を順番に実行するには、従来のコールバック地獄を作ることになりました。</p>

<pre class="brush: js notranslate">doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
</pre>

<p>モダンな関数を使えば、その代わりに戻り値の Promise にコールバックを付加して Promise チェーンとして記述できます。</p>

<pre class="brush: js notranslate">doSomething()
.then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
</pre>

<p> <code>then</code> 関数の引数はオプション(必須ではない)です。また、<code>catch(failureCallback)</code><code>then(null, failureCallback)</code> の短縮形です。記述には<a href="/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions">アロー関数</a>を使っても構いません。</p>

<pre class="brush: js notranslate">doSomething()
.then(result =&gt; doSomethingElse(result))
.then(newResult =&gt; doThirdThing(newResult))
.then(finalResult =&gt; {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
</pre>

<p><strong>重要:</strong> コールバック関数から処理結果を返すのを忘れないでください。さもないと後続のコールバック関数からその処理結果を利用することができなくなります (アロー関数を使った <code>() =&gt; x</code> は <code>() =&gt; { return x; }</code> の短縮形です)。</p>

<h3 id="Chaining_after_a_catch" name="Chaining_after_a_catch">catch後のチェーン</h3>

<p>失敗、つまり <code>catch</code> の後にチェーンするのも可能で、これはチェーン内の動作が失敗した後でも新しい動作を行うのに便利です。次の例を読んでください:</p>

<pre class="brush: js notranslate">new Promise((resolve, reject) =&gt; {
    console.log('Initial');

    resolve();
})
.then(() =&gt; {
    throw new Error('Something failed');

    console.log('Do this');
})
.catch(() =&gt; {
    console.log('Do that');
})
.then(() =&gt; {
    console.log('Do this whatever happened before');
});</pre>

<p>これは下記のテキストを出力します:</p>

<pre class="notranslate">Initial
Do that
Do this whatever happened before</pre>

<p><strong>注意:</strong><q>Do this</q> のテキストは <q>Something failed</q> エラーが reject を引き起こしたため出力されないことに注意してください。</p>

<h2 id="Error_propagation" name="Error_propagation">エラーの伝播</h2>

<p>以前のコールバック地獄形式の記述方法では <code>failureCallback</code> を 3 回書く必要がありましたが、Promise チェーンでは <code>failureCallback</code> は 1 回で済みます。</p>

<pre class="brush: js notranslate">doSomething()
.then(result =&gt; doSomethingElse(result))
.then(newResult =&gt; doThirdThing(newResult))
.then(finalResult =&gt; console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
</pre>

<p>例外が発生すると、ブラウザーはチェーンをたどって <code>.catch()</code> ハンドラーか <code>onRejected</code> を探します。この振る舞いは同期的なコードの動作と非常によく類似しています。</p>

<pre class="brush: js notranslate">try {
  const result = syncDoSomething();
  const newResult = syncDoSomethingElse(result);
  const finalResult = syncDoThirdThing(newResult);
  console.log(`Got the final result: ${finalResult}`);
} catch(error) {
  failureCallback(error);
}
</pre>

<p>ECMAScript 2017 のシンタックスシュガー <a href="/ja/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> を使えば、完全にそっくりのコードになります。</p>

<pre class="brush: js notranslate">async function foo() {
  try {
    const result = await doSomething();
    const newResult = await doSomethingElse(result);
    const finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch(error) {
    failureCallback(error);
  }
}
</pre>

<p>async/await は Promise の上に成り立っています。例えば上記の <code>doSomething()</code> はこれまでと同じ(Promise を返す)関数です。この書き方の詳細については<a href="https://developers.google.com/web/fundamentals/getting-started/primers/async-functions">こちら</a>をご覧ください。</p>

<p>Promise は例外やプログラミングエラーを含むすべてのエラーをとらえることで、コールバック地獄の根本的な問題を解決します。これは非同期処理を合成するのに不可欠です。</p>

<h2 id="Promise_rejection_events" name="Promise_rejection_events">Promise の失敗イベント</h2>

<p>Promise が失敗するたびに、グローバルスコープ(通常 {{domxref("window")}} オブジェクトか、Web Worker 内ならば <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Worker" title="Worker インターフェイス of the Web Workers API represents a background task that can be created via script, which can send messages back to its creator."><code>Worker</code></a> か Worker ベースのインターフェイスをもつオブジェクト)に以下の 2 つのイベントのどちらかが送られます:</p>

<dl>
 <dt><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Window/rejectionhandled_event" title="The rejectionhandled event is sent to the script's global scope (usually window but also Worker) whenever a JavaScript Promise is rejected but after the promise rejection has been handled."><code>rejectionhandled</code></a></dt>
 <dd>Promise が失敗したとき、それが <code>reject</code> 関数などによって処理されたあとに送られる。</dd>
 <dt><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Window/unhandledrejection_event" title="The unhandledrejection event is sent to the global scope of a script when a JavaScript Promise that has no rejection handler is rejected; typically, this is the window, but may also be a Worker."><code>unhandledrejection</code></a></dt>
 <dd>Promise が失敗して、ハンドラーが存在しないときに送られる。</dd>
</dl>

<p>いずれの場合でも、イベントオブジェクト( <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/PromiseRejectionEvent" title="PromiseRejectionEvent インターフェイス represents events which are sent to the global script context when JavaScript Promises are rejected."><code>PromiseRejectionEvent</code></a> 型)は失敗した Promise を表す <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/PromiseRejectionEvent/promise" title="The PromiseRejectionEvent interface's promise read-only property indicates the JavaScript Promise which was rejected. You can examine the event's PromiseRejectionEvent.reason property to learn why the promise was rejected."><code>promise</code></a> プロパティと、その Promise が失敗した理由を表す <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/PromiseRejectionEvent/reason" title="The read-only PromiseRejection property reason read-only property is any JavaScript value or Object which provides the reason passed into Promise.reject(). This in theory provides information about why the promise was rejected."><code>reason</code></a> プロパティを持ちます。</p>

<p>これらのイベントを使えば、Promise のエラーハンドラーのフォールバックを指定することができ、また Promise を管理する際の問題をデバッグするのにも役立ちます。これらのイベントのハンドラーはコンテキストごとにグローバルであり、どこから発生したかに関わらず、すべてのエラーは同じイベントハンドラーによって処理されます。</p>

<p>特に便利なケースとして、{{Glossary("Node.js")}} 用のコードを書いているときにプロジェクト内のモジュールで Promise が失敗しハンドルされないことがよくあります。これらは Node.js の実行環境によりコンソールに出力されます。これらの失敗を分析したりハンドラーを設定したいとき、あるいは単にコンソールがこれらで埋め尽くされないようにしたいとき、以下のように <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Window/unhandledrejection_event" title="The unhandledrejection event is sent to the global scope of a script when a JavaScript Promise that has no rejection handler is rejected; typically, this is the window, but may also be a Worker."><code>unhandledrejection</code></a> イベントのハンドラーを追加することができます。</p>

<pre class="brush: js notranslate">window.addEventListener("unhandledrejection", event =&gt; {
  /* ここで該当の Promise を event.promise で、失敗の理由を
     event.reason で取得して調べることができます */

  event.preventDefault();
}, false);</pre>

<p>イベントの <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Event/preventDefault" title="The Event interface's preventDefault() method tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be."><code>preventDefault()</code></a> メソッドを呼び出すことによって、失敗した Promise がハンドルされないときの JavaScript の実行環境のデフォルトの動作を防ぐことができます。特に Node.js がそうですが、通常はデフォルトの動作ではエラーがコンソールに出力されます。</p>

<p>当然ながら理想的には、これらのイベントを捨てる前に失敗した Promise を調べて、いずれもコードのバグによるものではないことを確かめるべきです。</p>

<h2 id="Creating_a_Promise_around_an_old_callback_API" name="Creating_a_Promise_around_an_old_callback_API">古いコールバック API をラップする Promise の作成</h2>

<p>{{jsxref("Promise")}} はコンストラクタを使って 1 から作ることもできます。これは古い API をラップする場合にのみ必要となるはずです。</p>

<p>理想的には、すべての非同期関数は Promise を返すはずですが、残念ながら API の中にはいまだに古いやり方で成功/失敗用のコールバックを渡しているものがあります。典型的な例としては <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeout" title="The documentation about this has not yet been written; please consider contributing!"><code>setTimeout()</code></a> 関数があります。</p>

<pre class="brush: js notranslate">setTimeout(() =&gt; saySomething("10 seconds passed"), 10*1000);
</pre>

<p>古い形式のコールバックと Promise の混在は問題を引き起こします。というのは、<code>saySomething()</code> が失敗したりプログラミングエラーを含んでいた場合にそのエラーをとらえられないからです。<code>setTimeout</code> にその責任があります。</p>

<p>幸いにも <code>setTimeout</code> を Promise の中にラップすることができます。ベストプラクティスは、問題のある関数を可能な限り低いレベルでラップした上で、二度と直接呼ばないようにするというものです。</p>

<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));

wait(10*1000).then(() =&gt; saySomething("10 seconds")).catch(failureCallback);
</pre>

<p>基本的に、Promise のコンストラクタには、手動で Promise を resolve もしくは reject できるようにする実行関数を渡します。<code>setTimeout()</code> は失敗することはないので、reject は省略しました。</p>

<h2 id="Composition" name="Composition">合成 (Composition)</h2>

<p>{{jsxref("Promise.resolve()")}} と {{jsxref("Promise.reject()")}} はそれぞれ既に resolve もしくは reject された Promise を手動で作成するショートカットで、たまに役立つことがあります。</p>

<p>{{jsxref("Promise.all()")}} と {{jsxref("Promise.race()")}} は同時並行で実行中の非同期処理を合成するためのツールです。</p>

<p>以下のように複数の処理を並行に開始し、すべてが終了するのを待つことができます。</p>

<pre class="brush: js notranslate">Promise.all([func1(), func2(), func3()])
.then(([result1, result2, result3]) =&gt; { /* result1, result2, result3 が使える */ });</pre>

<p>以下のように工夫すれば、逐次実行をする直列的な合成も記述することができます。</p>

<pre class="brush: js notranslate">[func1, func2].reduce((p, f) =&gt; p.then(f), Promise.resolve())
.then(result3 =&gt; { /* result3 が使える */ });</pre>

<p>基本的に、これは非同期関数の配列を  <code><span class="pun">Promise.resolve().then(</span><span class="pln">func1).then(</span><span class="pln">func2</span><span class="pun">).then(func3);</span></code><span class="pun"> と同等の Promise チェーンへと reduce しています。</span></p>

<p>このような処理は以下のように、関数型プログラミングでよくある再利用可能な合成関数にすることがすることができます。</p>

<pre class="brush: js notranslate">const applyAsync = (acc,val) =&gt; acc.then(val);
const composeAsync = (...funcs) =&gt; x =&gt; funcs.reduce(applyAsync, Promise.resolve(x));</pre>

<p><code>composeAsync</code> 関数は任意の個数の関数を引数として受け取って、1本のパイプラインとして合成された関数を返します。この関数に渡された初期値は合成された関数を通過していきます。</p>

<pre class="brush: js notranslate">const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);</pre>

<p>ECMAScript 2017 では直列的な合成は async/await でもっと単純に書くことができます。</p>

<pre class="brush: js notranslate">let result;
for (const f of [func1, func2, func3]) {
  result = await f(result);
}
/* 最終的な結果(result3)が使える */</pre>

<h2 id="Timing" name="Timing">タイミング</h2>

<p>想定外の事態とならないよう、たとえすでに resolve された Promise であっても、<code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> に渡される関数が同期的に呼ばれることはありません。</p>

<pre class="brush: js notranslate">Promise.resolve().then(() =&gt; console.log(2));
console.log(1); // 1, 2
</pre>

<p>渡された関数は、すぐに実行されるのではなくマイクロタスクのキューに入れられます。現在のイベントループの終わりにこのキューは空になったときに、この関数が実行されます(つまりかなり早い段階です)。</p>

<pre class="brush: js notranslate">const wait = ms =&gt; new Promise(resolve =&gt; setTimeout(resolve, ms));

wait().then(() =&gt; console.log(4));
Promise.resolve().then(() =&gt; console.log(2)).then(() =&gt; console.log(3));
console.log(1); // 1, 2, 3, 4</pre>

<h2 id="Nesting" name="Nesting">ネスト</h2>

<p>単純な Promise チェーンならば、ネストは不用意な合成の結果生まれるものなので、ネストせずに平らにしておくのがベストです。<a href="#Common_mistakes">よくある間違い</a>を参照してください。</p>

<p>ネストとは <code>catch</code> ステートメントのスコープを制限するための制御構造です。正確には、ネストされた <code>catch</code> はそのスコープ内の失敗しかキャッチせず、Promise チェーン上でスコープ外のエラーには反応しません。正しく使えばより正確にエラーからの回復ができるようになります。</p>

<pre class="brush: js notranslate">doSomethingCritical()
.then(result =&gt; doSomethingOptional(result)
  .then(optionalResult =&gt; doSomethingExtraNice(optionalResult))
  .catch(e =&gt; {})) // オプションの処理が失敗すれば無視して進める
.then(() =&gt; moreCriticalStuff())
.catch(e =&gt; console.log("Critical failure: " + e.message));</pre>

<p>インデントではなく外側の括弧 <code>()</code> によってオプションの処理がネストされていることに注意してください。</p>

<p>内側の <code>catch</code> ステートメントは <code>doSomethingOptional()</code> と <code>doSomethingExtraNice()</code> からの失敗だけをキャッチし、キャッチしたあと <code>moreCriticalStuff()</code> へと処理が続きます。重要なのは、もし <code>doSomethingCritical()</code> が失敗したらそのエラーは最後の <code>catch</code> によってだけキャッチされるということです。</p>

<h2 id="Common_mistakes" name="Common_mistakes">よくある間違い</h2>

<p>Promise チェーンを合成するときは以下のようなよくある間違いに気をつける必要があります。以下の例にいくつかの間違いが含まれています。</p>

<pre class="brush: js example-bad notranslate">// 悪い例。間違いを 3 つ見つけてください。

doSomething().then(function(result) {
  doSomethingElse(result) // 内側のチェーンから Promise を返していない + 不必要なネスト
  .then(newResult =&gt; doThirdThing(newResult));
}).then(() =&gt; doFourthThing());
// チェーンの最後を catch で終わらせていない
</pre>

<p>最初の間違いは適切にチェーンを構成できていないことです。これは、新しい Promise を作成したがそれを返すのを忘れているときに起きます。結果としてチェーンは壊れ、2 つのチェーンが独立に実行されることになります。これはつまり <code>doFourthThing()</code> は <code>doSomethingElse()</code> や <code>doThirdThing()</code> の終了を待たないことになり、おそらく意図せず並行して実行されることになります。別々のチェーンでは別々のエラーハンドリングが行われるため、キャッチされないエラーが発生することになります。</p>

<p>2 つ目の間違いは不必要にネストしていることであり、1 つめの間違いを可能にしているものでもあります。ネストするということは内側のエラーハンドラーが制限されるということであり、もしこれが意図していないものであれば、エラーがキャッチされないということが起こりえます。これの変化形で <a href="https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it">Promise コンストラクターアンチパターン</a>というものがあり、ネストに加えて、Promise を既に使用しているコードを不必要な Promise コンストラクターでラップするというものです。</p>

<p>3 つ目の間違いはチェーンを <code>catch</code> で終わらせていないことです。ほとんどのブラウザーではそのようなチェーンは Promise の失敗がキャッチされないことになります。</p>

<p>よい経験則としては、Promise チェーンは常に <code>return</code> するか <code>catch</code> で終わらせ、新しい Promise を得るたびにすぐに <code>return</code> してチェーンを平らにすることです。</p>

<pre class="brush: js example-good notranslate">doSomething()
.then(function(result) {
  return doSomethingElse(result);
})
.then(newResult =&gt; doThirdThing(newResult))
.then(() =&gt; doFourthThing())
.catch(error =&gt; console.log(error));
</pre>

<p><code>() =&gt; x</code> は <code>() =&gt; { return x; }</code> の短縮形であることに注意してください。</p>

<p>これで適切なエラーハンドリングがされた 1本のチェーンができました。</p>

<p><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> を使えば、すべてではないにしてもほとんどの問題は解決しますが、このシンタックスで最もよくある間違いが <code><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function">await</a></code> キーワードを忘れることであるという欠点があります。</p>

<h2 id="When_promises_and_tasks_collide" name="When_promises_and_tasks_collide">Promises とタスクが衝突するとき</h2>

<p>(イベントとコールバックのような) Promise とタスクが予知できない順序で発火するような状況に陥る場合、Promise が条件付きで作成されて Promise の状態をチェックしたり帳尻合わせしたりするマイクロタスクを利用できることがあります。</p>

<p>マイクロタスクでこの問題を解決できると考えたなら、<a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/HTML_DOM_API/Microtask_guide">microtask guide</a> を見て、関数をマイクロタスクでキューに入れる <a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/queueMicrotask" title="The queueMicrotask() method, which is exposed on the Window or Worker interface, queues a microtask to be executed at a safe time prior to control returning to the browser's event loop."><code>queueMicrotask()</code></a> の使い方を学んでください。</p>

<h2 id="See_also" name="See_also">関連項目</h2>

<ul>
 <li>{{jsxref("Promise.then()")}}</li>
 <li><a href="https://wiki.developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a></li>
 <li><a href="http://promisesaplus.com/">Promises/A+ specification</a></li>
 <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li>
 <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c#.dzlqh6ski">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li>
 <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</a></li>
 <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li>
</ul>

<p>{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</p>