async・awaitで例外処理を行う場合、メソッドチェーンで受け取る方法と、try-catchで受け取る方法があります。
これらの方法について、紹介していこうと思います。
サンプルコードはNode.jsで実行しています。
----
awaitで呼び出される関数では、Promiseオブジェクトを返す必要があります。
通常はresolveで返しますが、例外処理を行う場合はrejectを返す必要があります。
これは、例外をメソッドチェーンで受け取る場合も、try-catchで受け取る場合も変わりません。
なお、rejectで返されたPromiseオブジェクトをメソッドチェーンでもtry-catchでも受け取らなかった場合は、UnhandledPromiseRejectionWarningが発生しプロセスが終了するので、注意が必要です。
----
rejectでPromiseオブジェクトを返された場合は、メソッドチェーン「.catch」で受け取ることが可能です。
「.catch」で受け取った場合は、「.catch」内の処理が実行され、戻り値は取得できません。
(戻り値はundefinedになります)
resolveで返された場合は、「.catch」内の処理が実行されません。
なお、メソッドチェーン「.catch」の前にメソッドチェーン「.then」を入れることで、resolveで返されたPromiseオブジェクトをこれで返すことができます。
「.then」で受け取った場合は、「.then」内の処理が実行され、戻り値は取得できません。
(戻り値はundefinedになります)
また、rejectで返された場合は、「.catch」の前に定義した「.then」内の処理が実行されません。
以下、サンプルコードです。
【サンプルコード】
・sample.js
function lightTask() {
console.log("light");
}
function heavyTask() {
// awaitで呼び出される関数ではpromiseオブジェクトを返す必要がある
return new Promise((resolve, reject) => {
const procedure = () => {
console.log("heavy");
// resolve(0); // ①
// reject(1); // ②
}
setTimeout(procedure, 1000);
});
}
// awaitを使用する関数にはasyncをつける
async function exection() {
let result = await heavyTask()
// .then((code) => { console.log("normal:" + code); }) // ③
// .catch((code) => { console.error("error:" + code); }) // ④
;
console.log("code:"+result);
lightTask();
}
exection();
【実行結果】
・①と③と④のコメントアウトを外した場合(resolveを.thenで受け取る)
C:\tmp>node sample.js
heavy
normal:0
code:undefined
light
C:\tmp>
・①と④のコメントアウトを外した場合(resolveを.thenで受け取らない)
C:\tmp>node sample.js
heavy
code:0
light
C:\tmp>
・②と③と④のコメントアウトを外した場合(rejectを.catchで受け取る)
C:\tmp>node sample.js
heavy
error:1
code:undefined
light
C:\tmp>
・参考:②と③のコメントアウトを外した場合(rejectを受け取らない)
C:\tmp>node sample.js
heavy
(node:9180) UnhandledPromiseRejectionWarning: 1
(node:9180) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This
error originated either by throwing inside of an async function without a catch
block, or by rejecting a promise which was not handled with .catch(). To termina
te the node process on unhandled promise rejection, use the CLI flag `--unhandle
d-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejectio
ns_mode). (rejection id: 1)
(node:9180) [DEP0018] DeprecationWarning: Unhandled promise rejections are depre
cated. In the future, promise rejections that are not handled will terminate the
Node.js process with a non-zero exit code.
C:\tmp>
----
rejectで返されたPromiseオブジェクトはtry-catchで受け取ることも可能です。
ただし、この場合、戻り値を参照しないように注意が必要で、参照してしまうとUnhandledPromiseRejectionWarningが発生しプロセスが終了してしまいます。
以下、サンプルコードです。
【サンプルコード】
・sample.js
function lightTask() {
console.log("light");
}
function heavyTask() {
// awaitで呼び出される関数ではpromiseオブジェクトを返す必要がある
return new Promise((resolve, reject) => {
const procedure = () => {
console.log("heavy");
reject(1);
}
setTimeout(procedure, 1000);
});
}
// awaitを使用する関数にはasyncをつける
async function exection() {
try {
let result = await heavyTask();
console.log("code:"+result);
} catch (e) {
console.error("error:"+e);
// console.log("code:"+result); // ⑤
}
lightTask();
}
exection();
【実行結果】
・そのまま実行した場合(rejectをtry-catchで受け取る)
C:\tmp>node sample.js
heavy
error:1
light
C:\tmp>
・参考:⑤のコメントアウトを外した場合(try-catchで受け取る際に戻り値参照)
C:\tmp>node sample.js
heavy
error:1
(node:1600) UnhandledPromiseRejectionWarning: ReferenceError: result is not defi
ned
at exection (C:\tmp\sample.js:23:25)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:1600) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This
error originated either by throwing inside of an async function without a catch
block, or by rejecting a promise which was not handled with .catch(). To termina
te the node process on unhandled promise rejection, use the CLI flag `--unhandle
d-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejectio
ns_mode). (rejection id: 1)
(node:1600) [DEP0018] DeprecationWarning: Unhandled promise rejections are depre
cated. In the future, promise rejections that are not handled will terminate the
Node.js process with a non-zero exit code.
C:\tmp>