6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年2月8日 JavaScript (JS Primer) Promise.prototype.thenとcatch

thenメソッドの使い方について具体的な例を紹介します。 thenメソッドのエイリアスでもあると言われているcatchメソッドについても勉強しましたのでその点もまとめていきます。

function dummyFetch(path) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (path.startsWith("/success")) {
                resolve({ body: `Response body of ${path}` });
            } else {
                reject(new Error("NOT FOUND"));
            }
        }, 1000 * Math.random());
    });
}
// `then`メソッドで成功時と失敗時に呼ばれるコールバック関数を登録
// /success/data のリソースは存在するので成功しonFulfilledが呼ばれる
dummyFetch("/success/data").then(function onFulfilled(response) {
    console.log(response); // => { body: "Response body of /success/data" }
}, function onRejected(error) {
    // この行は実行されません
});
// /failure/data のリソースは存在しないのでonRejectedが呼ばれる
dummyFetch("/failure/data").then(function onFulfilled(response) {
    // この行は実行されません
}, function onRejected(error) {
    console.log(error); // Error: "NOT FOUND"
});

復習

ここではonFulfilledを明示するためにfuctionキーワード使って実装しています。 ArrowFunctionは無名関数にしか使用できないためです。

// ArrowFunctionで書くならば
dummyFetch("/success/data").then((response) => {})

Promiseのthenメソッドは成功(onFulfilled)と失敗(onRejected)のコールバック関数の2つを受け取りますが、どちらの引数も省略できます。

次のコードのdelay関数は一定時間後に解決(resolve)されるPromiseインスタンスを返します。 このPromiseインスタンスに対してthenメソッドで成功時のコールバック関数だけを登録しています。

つまり、これまではthenメソッドに成功時、エラー時のコールバック関数の処理を登録していましたが、引数を一つに省略することが可能ということですね。 下の例はエラー時の引数を持っていない例です。

function delay(timeoutMs) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, timeoutMs);
    });
}
// `then`メソッドで成功時のコールバック関数だけを登録
delay(10).then(() => {
    console.log("10ミリ秒後に呼ばれる");
});

一方、thenメソッドでは失敗時のコールバック関数だけの登録もできます。

このときthen(undefined, onRejected)のように第1引数にはundefinedを渡す必要があります。 then(undefined, onRejected)と同様のことを行う方法としてPromiseのcatchメソッドが用意されています。

次のコードではthenメソッドとcatchメソッドで失敗時のエラー処理をしていますが、どちらも同じ意味となります。 thenメソッドにundefinedを渡すのはわかりにくいため、失敗時の処理だけを登録する場合はcatchメソッドの利用を推奨しています。

function errorPromise(message) {
    return new Promise((resolve, reject) => {
        reject(new Error(message));
    });
}
// 非推奨: `then`メソッドで失敗時のコールバック関数だけを登録
errorPromise("thenでエラーハンドリング").then(undefined, (error) => {
    console.log(error.message); // => "thenでエラーハンドリング"
});
// 推奨: `catch`メソッドで失敗時のコールバック関数を登録
errorPromise("catchでエラーハンドリング").catch(error => {
    console.log(error.message); // => "catchでエラーハンドリング"
});

まとめ

  • thenメソッドの引数は省略することができる
  • 非同期処理を失敗時の処理をthenメソッドで呼び出す場合、第一引数にundefined を持たせる必要があり、わかりにくくなってしまうため、失敗時の処理だけを登録したい場合はcatchメソッドを使う。

参考

JS primer Promise.prototype.thenとPromise.prototype.catch