JavaScriptのPromise、async/await、fetch

JavaScriptのPromise、async/await、fetch:実行できる15の例 | We.Inc

Promise、async/await、fetch APIを、1ステップずつ進むイベントループのタイムラインと、編集して実行できる15の例で解説します。JSON、フォーム、エラー、並列リクエスト、AbortController、リトライを扱います。

JavaScriptのPromise、async/await、fetch

Promiseは、後で届く結果を表します。async関数はPromiseを返し、awaitはPromiseが確定するまでその関数を一時停止します。fetch(url)はResponseのPromiseを返します。response.okを確認してから、await response.json()を実行しましょう。awaitはtryとcatchで囲み、並列リクエストにはPromise.allを、キャンセルにはAbortControllerを使います。

ほとんどのページで必要なパターン

まずタイムラインで、awaitの後のコードがなぜそれより先に実行されることがあるのかを確認しましょう。その後、どの例でも編集するとその場で再実行されます。ここでのリクエストはdata: URLや疑似サーバーを使うため、ブラウザーの外には何も送信されません。

よくある質問

Promiseとasync/awaitの違いは何ですか?

できることに違いはありません。async/awaitはPromiseの上に作られています。async関数は常にPromiseを返し、awaitはPromiseの中身を取り出します。普通の手順どおりのコードのように読めるため、tryとcatchでエラーを扱いやすくなります。

fetchが404でエラーを投げないのはなぜですか?

サーバーは応答を返しているので、fetchはどんなHTTP応答でもリクエストは成功したとみなします。rejectされるのは、ネットワーク障害かリクエストがキャンセルされた場合だけです。response.okやresponse.statusは自分で確認してください。

0を指定したsetTimeoutが、解決済みのPromiseより後に実行されるのはなぜですか?

Promiseのコールバックはマイクロタスクキューに入り、現在のスクリプトの後に完全に空になるまで実行されます。タイマーのコールバックはタスクなので、イベントループの次の周回まで待ちます。

fetchリクエストをキャンセルするには?

AbortControllerを作成し、fetchのオプションにcontroller.signalを渡して、controller.abort()を呼び出します。fetchのPromiseは、AbortErrorという名前のエラーでrejectされます。

トップレベルでawaitを使えますか?

はい、JavaScriptモジュール(script type="module"またはバンドルされたESモジュール)の中なら使えます。従来のスクリプトでは、コードをasync関数で囲みましょう。

よく見るエラー

実際のサイトで使う

Promiseとasync/await

1. 何がいつ実行されるか

まず同期的な行が実行され、次にキューに入ったすべてのPromiseのコールバック(マイクロタスク)、その後にタイマー(タスク)が実行されます。順番を変えて、もう一度実行してみましょう。

2. Promiseを作る

Promiseが確定するのは1回だけです。resolveは値を、rejectはエラーを渡します。thenとcatchは後で実行され、すぐには実行されません。

3. 同じことをasyncとawaitで

awaitが一時停止するのは、それが書かれたasync関数だけです。main()の呼び出しの次の行は、mainが終わる前に実行されます。

4. try、catch、finallyでのエラー処理

async関数の中では、rejectされたawaitが例外を投げるため、通常のtryとcatchが使えます。スピナーを隠すのはfinallyで行います。

実際のWebサイトでのfetch

5. fetchでJSONを読み込む

fetchはResponseを返します。.json()は本文を読み取って解析するもので、これが2つ目のawaitになります。この例はdata: URLを使うのでオフラインでも動きます。

6. fetchにとって404はエラーではない

fetchがrejectされるのは、リクエスト自体ができない場合(オフライン、ブロック、不正なURL)だけです。404や500はokがfalseの状態で普通にresolveされるため、必ず確認しましょう。

7. fetchでフォームを送信する

FormDataは名前の付いたすべてのフィールドを読み取ります。ここではリクエストを作成しますが送信はせず、本文を表示して、サーバーが受け取る内容を正確に確認できるようにしています。

8. JSONをPOSTする

JSONを送るには、文字列化してContent-Typeヘッダーを自分で設定します。普通のオブジェクトに対して、fetchはどちらもやってくれません。

複数のリクエストを同時に

どのPromiseヘルパーを使うか

9. 逐次実行と並列実行

1回ずつawaitすると待ち時間が合計されます。すべてを開始してからPromise.allをawaitすれば、最も遅いものの分だけ待てば済みます。

10. Promise.allとPromise.allSettled

Promise.allは1つでも失敗するとすぐにrejectされます。allSettledはすべてを待ち、どれが成功したかを教えてくれるので、独立したウィジェットのあるダッシュボードに向いています。

11. 大量のリクエストを少しずつ

何百ものリクエストを一度に送るとレート制限に引っかかることがあります。この小さなプールは、同時に処理中のリクエストを最大3つに抑えます。

キャンセル、タイムアウト、リトライ

12. AbortControllerでキャンセル

fetchにcontroller.signalを渡し、abort()を呼び出すと停止します。PromiseはAbortErrorでrejectされますが、通常は無視してかまいません。

13. タイムアウトで諦める

AbortSignal.timeout(ms)は、自動的に中断するシグナルを作ります。fetchではエラー名がTimeoutErrorになるため、ユーザーによるキャンセルと区別できます。

14. バックオフ付きのリトライ

リトライするのは、タイムアウトや503のように一時的な可能性があるエラーだけにし、負荷の高いサーバーが回復できるよう、毎回待ち時間を長くします。

15. 古い結果を出さない入力中の検索

入力が止まるのを待ち、新しいリクエストを開始するときに前のリクエストを中断します。こうすれば、遅れて届いた古い応答が新しい応答を上書きすることはありません。

読み取りたいレスポンスがありますか?貼り付けて確認できるのが

JSONフォーマッター

イベントループのタイムライン

コールスタック

マイクロタスク

タスクキュー

コンソール

ステップ {i} / {n}。

戻る

次のステップ

一時停止

再生

リセット

無料で始める · クレジットカード不要

関連: ガイド|Webマーケティングと集客を学ぶ

製品

ご利用いただける方

機能

リソース

会社情報

サイトマップを見る