Promise.prototype.catch()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
catch()
は Promise
オブジェクトのメソッドで、プロミスが拒否されたときに呼び出される関数をスケジュールします。これは即座に同等の Promise
オブジェクトを返すので、他のプロミスのメソッドを連鎖 して呼び出すことができます。これは Promise.prototype.then(undefined, onRejected)
の省略形です。
試してみましょう
構文
catch(onRejected)
catch((reason) => {
// 拒否ハンドラー
})
引数
onRejected
-
Promise
が拒否された時に呼び出されるFunction
です。この関数は 1 つの引数、 拒否された理由 を取ります。
返値
新しい Promise
を返します。この新しいプロミスは、現在のプロミスの状態に関係なく、返すときには常に待機状態です。onRejected
がエラーを発生させるか、それ自身が拒否されたプロミスを返す場合、最終的に拒否されます。そうでなければ、最終的に履行されます。
解説
catch
メソッドは複合したプロミスの複合のエラー処理に使用されます。これは Promise
を返すので、姉妹メソッドである then()
と同様の方法で連鎖が可能です。
もしプロミスが拒否され、呼び出すべき拒否ハンドラーがない場合(ハンドラーは then()
, catch()
, finally()
のいずれかを通して装着されます)、拒否イベントはホストから表面化されます。ブラウザーでは、これは unhandledrejection
イベントとして発生します。もし、拒否されたプロミスにハンドラーが装着され、その拒否がすでに unhandledrejection
イベントを発生していた場合、別の rejectionhandled
イベントが発行されます。
catch()
は内部的に、呼び出されたオブジェクトに対して then()
を呼び出し、引数として undefined
と onRejected
を渡します。その呼び出された値がそのまま返されます。これは、メソッドをラップすればオブザーバーで監視することができます。
// 元の Promise.prototype.then/catch をログを追加するだけ上書きする。
((Promise) => {
const originalThen = Promise.prototype.then;
const originalCatch = Promise.prototype.catch;
Promise.prototype.then = function (...args) {
console.log("Called .then on %o with arguments: %o", this, args);
return originalThen.apply(this, args);
};
Promise.prototype.catch = function (...args) {
console.error("Called .catch on %o with arguments: %o", this, args);
return originalCatch.apply(this, args);
};
})(Promise);
// 解決済みのプロミスに対する catch の呼び出し
Promise.resolve().catch(function XXX() {});
// ログ出力:
// Called .catch on Promise{} with arguments: Arguments{1} [0: function XXX()]
// Called .then on Promise{} with arguments: Arguments{2} [0: undefined, 1: function XXX()]
つまり、undefined
を渡しても、返されたプロミスは拒否されるため、最終的にプロミスが拒否されないようにするための関数を渡さなければなりません。
catch()
は then()
を呼び出すだけなので、サブクラス化に対応しています。
例
catch メソッドの使用とチェーン化
const p1 = new Promise((resolve, reject) => {
resolve("Success");
});
p1.then((value) => {
console.log(value); // "Success!"
throw new Error("oh, no!");
})
.catch((e) => {
console.error(e.message); // "oh, no!"
})
.then(
() => console.log("after a catch the chain is restored"),
() => console.log("Not fired due to the catch"),
);
// 以下は、上記と同様に動作します
p1.then((value) => {
console.log(value); // "Success!"
return Promise.reject("oh, no!");
})
.catch((e) => {
console.error(e); // "oh, no!"
})
.then(
() => console.log("after a catch the chain is restored"),
() => console.log("Not fired due to the catch"),
);
エラーが発生したことを知る
エラーが発生すると、たいていの場合 catch()
メソッドが呼び出されます。
const p1 = new Promise((resolve, reject) => {
throw new Error("Uh-oh!");
});
p1.catch((e) => {
console.error(e); // "Uh-oh!"
});
非同期関数内で発生したエラーは、捕捉されないエラーとして扱われます。
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
throw new Error("Uncaught Exception!");
}, 1000);
});
p2.catch((e) => {
console.error(e); // これは呼び出されない
});
resolve
が呼び出された後に発生したエラーは無視されます。
const p3 = new Promise((resolve, reject) => {
resolve();
throw new Error("Silenced Exception!");
});
p3.catch((e) => {
console.error(e); // これは呼び出されない
});
プロミスが履行されたときは catch() は呼び出されない
// onReject を呼び出さないプロミスを作る
const p1 = Promise.resolve("calling next");
const p2 = p1.catch((reason) => {
// これは呼び出されない
console.error("catch p1!");
console.error(reason);
});
p2.then(
(value) => {
console.log("next promise's onFulfilled");
console.log(value); // 次を呼び出し
},
(reason) => {
console.log("next promise's onRejected");
console.log(reason);
},
);
仕様書
Specification |
---|
ECMAScript Language Specification # sec-promise.prototype.catch |
ブラウザーの互換性
BCD tables only load in the browser