JavaScriptのcatchってなに?Promiseの失敗を受け取ってみよう

こんにちは、さるまりんです。

前回は、JavaScriptの then() について見てきました。

Promiseは、あとで結果が返ってくることを表すオブジェクトでしたね。

そして、Promiseの結果を受け取るときに使うのが、then() でした。

const promise = new Promise((resolve) => {
    setTimeout(() => {
        resolve("できました!");
    }, 1000);
});

promise.then((result) => {
    console.log(result);
});

このコードでは、1秒後に "できました!" という結果が返ってきます。

その結果を then() の中で受け取っているわけです。

今回は、その続きです。

Promiseは、いつも成功するとは限りません。処理がうまくいかないこともあります。エラーというヤツです。

そんなときに使うのが、catch() です。


Promiseは失敗することもあります

Promiseは、あとで結果が返ってくることを表します。

ただ、その「結果」は成功だけではありません。

  • データを取りに行ったけれど、取得できなかった
  • ファイルを読み込もうとしたけれど、見つからなかった
  • 通信しようとしたけれど、失敗した

ということもあります。

プログラムを書いていると、「うまくいったとき」だけではなく、「うまくいかなかったとき」のことも考える必要があります。

Promiseでは、この失敗を表すために reject を使います。


resolveは成功、rejectは失敗

前回のPromiseでは、resolve を使いました。

const promise = new Promise((resolve) => {
    resolve("できました!");
});

resolve は、成功した結果を返すためのものです。

一方で、Promiseには reject もあります。

const promise = new Promise((resolve, reject) => {
    reject("失敗しました");
});

reject は、失敗したことを伝えるためのものです。

resolve が成功。
reject が失敗。

まずは、このくらいで見ておくと分かりやすいと思います。


catchで失敗を受け取ります

では、reject されたPromiseを受け取ってみます。

const promise = new Promise((resolve, reject) => {
    reject("失敗しました");
});

promise.catch((error) => {
    console.log(error);
});

実行すると、次のように表示されます。

失敗しました

reject("失敗しました") で渡した値を、catch() の中で受け取っているわけですね。

ここでは、受け取った値に error という名前をつけています。

(error) => {
    console.log(error);
}

この error には、reject() に渡した値が入っています。


thenとcatchをつなげて書きます

Promiseでは、then()catch() をつなげて書くことがよくあります。

const promise = new Promise((resolve, reject) => {
    reject("失敗しました");
});

promise
    .then((result) => {
        console.log(result);
    })
    .catch((error) => {
        console.log(error);
    });

成功したら then() の中が動き、失敗したら catch() の中が動きます。

今回のコードでは reject() を呼び出しているので、then() ではなく catch() の方が動きます。

失敗しました

つまり、then() は成功したとき、catch() は失敗したとき、と分けて考えることができます。


成功する場合も見てみます

今度は、成功する場合も見てみましょう。

const promise = new Promise((resolve, reject) => {
    resolve("成功しました");
});

promise
    .then((result) => {
        console.log(result);
    })
    .catch((error) => {
        console.log(error);
    });

この場合は resolve() を呼び出しているので、then() の中が動きます。

成功しました

catch() の中は動きません。

成功は then()、失敗は catch() で受け取る。この流れが見えてくると、Promiseの動きが少し分かりやすくなります。


条件によって成功と失敗を分けてみます

もう少しだけ、実際の処理に近い形にしてみます。

const promise = new Promise((resolve, reject) => {
    const success = false;

    if (success) {
        resolve("データを取得しました");
    } else {
        reject("データを取得できませんでした");
    }
});

promise
    .then((result) => {
        console.log(result);
    })
    .catch((error) => {
        console.log(error);
    });

ここでは、success という変数を使っています。

const success = false;

successtrue なら成功。
successfalse なら失敗。

今回は false なので、reject("データを取得できませんでした") が実行されます。

データを取得できませんでした

successtrue に変えると、今度は resolve() が実行されます。

const success = true;

すると、次のように表示されます。

データを取得しました

成功したときと失敗したときで、処理の流れが変わるのが分かりますね。


catchは途中で起きたエラーも受け取ります

catch() が受け取るのは、reject() で渡した失敗だけではありません。

Promiseの処理や、その前にある then() の中でエラーが起きた場合も、後ろにつないだ catch() で受け取れます。

Promise.resolve("データを取得しました")
    .then((result) => {
        console.log(result);
        throw new Error("表示中にエラーが起きました");
    })
    .catch((error) => {
        console.log(error.message);
    });

throw new Error() は、自分でエラーを発生させる書き方です。

ここでは then() の中でエラーが起きますが、その後ろにある catch() が受け止めてくれます。

データを取得しました
表示中にエラーが起きました

このように、catch() はPromiseの一連の処理で起きた失敗を受け止める場所になります。


実際にはErrorオブジェクトを使うことが多いです

ここまでは動きを分かりやすくするために、reject() に文字列を渡してきました。

reject("失敗しました");

実際のコードでは、次のように Error オブジェクトを渡すことがよくあります。

const promise = new Promise((resolve, reject) => {
    reject(new Error("失敗しました"));
});

promise.catch((error) => {
    console.log(error.message);
});

Error オブジェクトには、エラーの内容や、どこでエラーが起きたかを調べるための情報が入ります。

まずは文字列の例で流れをつかみ、実際にコードを書くときは new Error() を使う、と覚えておくとよさそうです。


catchがあると、失敗したときの動きを書けます

catch() が大切なのは、失敗したときにどうするかを書けるからです。

例えば、何かのデータを取得する処理があったとします。

成功したら、そのデータを画面に表示する。失敗したら、「取得できませんでした」と表示する。

こういう分け方ができると、プログラムは少し親切になります。

失敗したときに何も起きないと、使っている人も、作っている自分も、「何が起きたんだろう?」となってしまいます。

promise
    .then((result) => {
        console.log("成功:", result);
    })
    .catch((error) => {
        console.log("エラー:", error);
    });

このようにしておくと、成功したときと失敗したときの両方を考えられます。


catchはエラーを受け止める場所です

catch という英単語には、「つかまえる」という意味があります。

Promiseの catch() も、失敗やエラーをつかまえる場所だと考えると分かりやすいです。

Promiseの中で何かがうまくいかなかった。そのままどこかへ行ってしまうのではなく、catch() で受け止める。そんなイメージです。

エラーが起きること自体は、悪いこととは限りません。

通信が切れることもあります。
データが見つからないこともあります。
入力された値が想定と違うこともあります。

大切なのは、失敗したときにどうするかです。そのための入り口として、catch() があります。


おわりに

今回は、JavaScriptの catch() について見てきました。

Promiseでは、成功したときに resolve() を使い、その結果を then() で受け取れます。

一方で、失敗したときには reject() を使い、その失敗を catch() で受け取れます。

resolve → then
reject  → catch

成功したら then()
失敗したら catch()

まずは、この流れを押さえておくとよさそうです。

Promiseは、最初は少し見慣れない書き方に感じるかもしれません。

けれど、「あとで結果が返ってくる」「成功したらthen」「失敗したらcatch」と分けて見ると、少しずつ形が見えてきます。

次は、Promiseをもう少し読みやすく書ける asyncawait について見ていきたいと思います。

読んでくださってありがとうございました!

それではまた。