【JavaScript入門】Promiseのインスタンスメソッド

 Promise は ES2015 で導入された “非同期処理を値として扱う” ためのオブジェクトです。ここでは Promise インスタンスが本来持っている3つのメソッド — .then().catch().finally() — を、表と実践的なコード例を使って体系的に学びます。「Promise チェーン」 と呼ばれる書き方の基本から、throw と reject() がもたらす制御フローの変化までを網羅し、日常的なフロントエンド開発で即使える知識として整理しましょう。ここで扱うサンプルはすべて日本語のメッセージを出力し、HTML + CSS + JavaScript だけで完結します。

1.インスタンスメソッドの全体像

メソッド主な役割戻り値の型コールバックが呼ばれる条件
.then(onFulfilled, onRejected)正常処理とエラー処理を分岐させるPromiseresolve() が呼ばれたとき → onFulfilledreject() が呼ばれたとき → onRejected
.catch(onRejected)エラー処理だけ受け持つPromise直前までに発生した reject() または throw
.finally(onFinally)成功・失敗を問わず必ず最後に実行Promise直前までのチェーンが 完了(解決/拒否どちらでも)したとき

1.1. .then() — 成功・失敗の分岐点

 .then() は「成功時はこうする/失敗時はこうする」を表現する最も基本的なメソッドです。2番目の引数(失敗時コールバック)は .catch() より先に評価されるため、局所的なエラー処理リトライ に便利です。

1.2. .catch() — エラー専用ハンドラ

 チェーンの途中で投げられた例外 (throw) や reject() は、次に現れる .catch() までスキップされます。try…catchcatch 節 と同じ感覚で使えます。

1.3. .finally() — 後片付けの一元化

 リソースの解放・ローディング表示の解除など、成否に関係なく実行したい処理 をまとめます。.finally() 内で返した値はチェーンに影響しない点に注意しましょう。

2.サンプルプログラムで理解する

ファイル名: promise-demo.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>⚡️ Promise インスタンスメソッド入門</title>
  <style>
    body{font-family:"Segoe UI",sans-serif;background:#f4f9ff;margin:2rem;}
    h1{font-size:1.8rem;text-align:center;margin-bottom:1rem;}
    #log{white-space:pre-line;background:#fff;border:1px solid #d0d0d0;
         border-radius:8px;padding:1rem;min-height:6rem;}
    button{padding:.6rem 1.2rem;border:none;border-radius:6px;
           background:#0078d4;color:#fff;font-weight:bold;cursor:pointer;}
    button:hover{opacity:.85;}
  </style>
</head>
<body>
  <h1>⚡️ Promise インスタンスメソッド入門</h1>
  <button id="runBtn">チェーンを実行</button>
  <div id="log"></div>

  <script>
  // 指定時間後に resolve / reject するユーティリティ
  const wait = (label, ok = true, ms = 120) =>
    new Promise((resolve, reject) => {
      setTimeout(() => {
        log(label);
        ok ? resolve() : reject();
      }, ms);
    });

  const log = msg => {
    const area = document.getElementById("log");
    area.textContent += msg + "\n";
  };

  document.getElementById("runBtn").onclick = () => {
    document.getElementById("log").textContent = ""; // ログ消去

    // A → (B成功 or B失敗) → C(失敗) → D(スキップ) → catch → finally
    wait("タスクA開始", true)
      .then(
        () => wait("タスクB成功", false),      // ここで reject
        () => wait("タスクB失敗")              // ← 今回は呼ばれない
      )
      .then(() => wait("タスクC成功"))         // スキップされる
      .catch(() => wait("タスクDエラー処理"))  // ここにジャンプ
      .finally(() => wait("タスクE後片付け"));
  };
  </script>
</body>
</html>

ブラウザの出力例

実行結果(ブラウザのコンソール

タスクA開始
タスクB成功
タスクDエラー処理
タスクE後片付け

ポイント解説

  1. B 成功内で false を渡しているので reject() が発火し、
    直後の .then()(タスク C)はスキップ → .catch() へジャンプ。
  2. .catch() を抜けたあとは必ず .finally() が呼ばれ、
    ここでログウィンドウを閉じるなどの “後始末” を一手に引き受けられます。
  3. wait()Promise を返す ため、チェーン全体が
    直列の非同期ステップ” として流れるイメージになります。

3.throw と reject() の比較

発生源どこで捕捉されるか伝播の仕組み
reject()直後の .then(onRejected) または .catch()明示的 にエラー状態を作る
throw.catch() か 2 番目以降の .then 引数同期例外 と同じく即座にジャンプ

throw は関数外に抜け出す点で「同期例外」の挙動を保ちつつ Promise チェーンに溶け込みます。

4.ベストプラクティス

  • 成功系失敗系.then() の2引数に混在させると可読性が低下しやすい。
    ⇒ 成功だけ .then() / 失敗だけ .catch() に分ける方が一般的。
  • 重複する終了処理は .finally() に一元化 し、コード量を削減。
  • Ajax や Fetch の連続呼び出しでは 返り値に次の Promise を返す ことで
    フローチャートをそのままコードに落とし込める。

まとめ

 Promise インスタンスメソッド3兄弟 .then() / .catch() / .finally() は、非同期の 成功・失敗・終了関数チェーン として宣言的に記述できる強力な API です。
 今回のサンプルを土台にして、複雑な API 呼び出しや UI のローディング制御を自信をもって設計できるようになりましょう。