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メソッドを使う。