PR

【JavaScript】Promiseとは?then・catch・finallyの使い方を初心者向けに解説

Promiseは非同期処理の結果を成功と失敗に分けて後から受け取る仕組みであることを表すアイキャッチ JavaScript

JavaScriptのPromiseとは、すぐには終わらない処理の結果を、あとで受け取るための仕組みです。

たとえば、サーバーからデータを取得する処理は、クリックした瞬間に結果が返ってくるとは限りません。通信には時間がかかりますし、失敗することもあります。

Promiseを使うと、そのような非同期処理に対して「成功したらこの処理」「失敗したらこの処理」「最後にこの処理」という形で、後続の処理を整理できます。

Promiseは「値そのもの」ではありません。まだ終わっていない処理の結果を、あとで受け取るための箱のようなものです。

この記事では、Promiseとは何か、thencatchfinallyの使い方、fetchasync/awaitとの関係を初心者向けに順番に解説します。

スポンサーリンク

まず結論:Promiseは非同期処理の結果をあとで受け取る仕組み

Promiseを最初に理解するときは、次のように考えると分かりやすいです。

非同期処理を始める
  ↓
Promiseが返る
  ↓
成功したら then
失敗したら catch
最後に finally

Promiseは、処理が終わる前に「将来の結果を表すオブジェクト」として返されます。MDNでも、Promiseは非同期処理の最終的な完了または失敗と、その結果の値を表すオブジェクトとして説明されています。

つまり、Promiseは「通信結果そのもの」ではなく、通信結果をあとで受け取るための窓口です。

Promiseが必要になる理由

JavaScriptでは、ブラウザ操作や通信処理など、すぐに終わらない処理がよく出てきます。代表例は、APIからデータを取得するfetchです。

もし通信が終わるまで画面全体が止まってしまうと、ユーザーは何も操作できません。そのためJavaScriptでは、時間がかかる処理を待っている間も、他の処理を進められるように非同期処理を使います。

ただし、非同期処理には問題があります。結果がいつ返るか分からないため、普通の変数代入の感覚で書くと、まだ結果がない状態を読んでしまいます。

そこでPromiseを使い、結果が返ってきたあとに実行する処理を登録します。

Promiseの3つの状態

Promiseには、処理の進み具合を表す状態があります。最初は細かい仕様名よりも、次の3つを押さえれば十分です。

状態意味初心者向けの見方
pendingまだ結果が出ていない処理中
fulfilled成功して結果が得られた成功した
rejected失敗して理由が返った失敗した

Promiseは最初はpendingです。その後、成功すればfulfilled、失敗すればrejectedになります。

この図では、Promiseを「非同期処理の結果をあとで受け取る流れ」として見てください。thenは成功、catchは失敗、finallyは最後の後片付けに対応します。

JavaScriptのPromiseが非同期処理の結果をthen、catch、finallyへ渡す流れを示す図
Promiseは、まだ終わっていない処理の結果を後から受け取るための約束として見ると理解しやすくなります。

then・catch・finallyの基本

Promiseでよく使うのは、thencatchfinallyの3つです。

メソッド使う場面ざっくりした意味
then()成功したとき結果を受け取って次の処理をする
catch()失敗したときエラーを受け取って処理する
finally()成功・失敗に関係なく最後後片付けをする

一番シンプルな形は次の通りです。

fetch("https://example.com/api/users")
  .then((response) => response.json())
  .then((users) => {
    console.log(users);
  })
  .catch((error) => {
    console.error("取得に失敗しました", error);
  })
  .finally(() => {
    console.log("処理が終わりました");
  });

thenは成功した結果を次へ渡します。catchは途中で失敗したときに呼ばれます。finallyは、成功しても失敗しても最後に実行されます。

Promiseチェーンとは?

Promiseでは、thenをつなげて処理を順番に書けます。このつながりをPromiseチェーンと呼ぶことがあります。

次の例では、最初のthenでレスポンスをJSONに変換し、次のthenで変換後のデータを使っています。

fetch("/users.json")
  .then((response) => response.json())
  .then((users) => users.filter((user) => user.active))
  .then((activeUsers) => {
    console.log(activeUsers);
  })
  .catch((error) => {
    console.error(error);
  });

ポイントは、前のthenで返した値が、次のthenへ渡されることです。

配列のfiltermapがあやふやな場合は、map・filter・reduceの違いも参考になります。

fetch APIとPromiseの関係

fetchは、HTTP通信を行うためのWeb APIです。そしてfetch()を呼び出すとPromiseが返ります。

そのため、fetchのコードではPromiseの理解がほぼ必須になります。

const promise = fetch("/api/users");

console.log(promise); // Promiseが入っている

この時点で得られるのは、ユーザー一覧そのものではありません。通信結果をあとで受け取るためのPromiseです。

fetchのGET・POSTの基本は、fetch APIとは?で詳しく解説しています。

async/awaitとの違い

async/awaitは、Promiseをより自然な順番で書くための構文です。Promiseと別物というより、Promiseを読みやすく扱うための書き方です。

Promiseチェーンで書くと次のようになります。

fetch("/api/users")
  .then((response) => response.json())
  .then((users) => console.log(users))
  .catch((error) => console.error(error));

同じ処理をasync/awaitで書くと、次のようになります。

async function loadUsers() {
  try {
    const response = await fetch("/api/users");
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error(error);
  }
}

awaitはPromiseの完了を待ち、その結果を取り出します。async/awaitの基本は、async/awaitとは?の記事で解説しています。

初心者がつまずきやすいポイント

つまずきまずこう理解する
Promiseを値そのものだと思うPromiseは将来の結果を表すオブジェクト
thenの中でreturnしない次のthenへ渡す値がなくなる
catchを書かない失敗時の動きが追いにくくなる
async/awaitならPromise不要と思うasync/awaitの裏側でもPromiseを扱っている

特に多いのは、thenの中で値を返し忘れることです。次の処理に値を渡したい場合は、returnを意識しましょう。

Promiseをどんな場面で使うのか

Promiseは、次のような非同期処理でよく使われます。

  • APIからデータを取得する
  • 一定時間後に処理する
  • ファイルや画像の読み込みを待つ
  • 複数の非同期処理を順番に実行する
  • 複数の非同期処理をまとめて待つ

ただし、最初からPromise.allPromise.raceなどをすべて覚える必要はありません。まずはthencatchfinallyと、async/awaitとの関係を押さえましょう。

関連して読みたい記事

まとめ

JavaScriptのPromiseは、非同期処理の結果をあとで受け取るための仕組みです。

  • thenは成功時の処理を書く
  • catchは失敗時の処理を書く
  • finallyは最後の後片付けを書く
  • async/awaitはPromiseを読みやすく扱う構文

Promiseを理解すると、fetchasync/awaitのコードがかなり読みやすくなります。最初は「まだ終わっていない処理の結果を、あとで受け取る約束」と考えれば十分です。

タイトルとURLをコピーしました