JavaScriptのasync・awaitについては以前の記事で簡単に触れましたが、例外処理を行う場合には別途注意が必要であるため、続きの記事を書きます。
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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で受け取る)
1 2 3 4 5 6 7 |
C:\tmp>node sample.js heavy normal:0 code:undefined light C:\tmp> |
・①と④のコメントアウトを外した場合(resolveを.thenで受け取らない)
1 2 3 4 5 6 |
C:\tmp>node sample.js heavy code:0 light C:\tmp> |
・②と③と④のコメントアウトを外した場合(rejectを.catchで受け取る)
1 2 3 4 5 6 7 |
C:\tmp>node sample.js heavy error:1 code:undefined light C:\tmp> |
・参考:②と③のコメントアウトを外した場合(rejectを受け取らない)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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で受け取る)
1 2 3 4 5 6 |
C:\tmp>node sample.js heavy error:1 light C:\tmp> |
・参考:⑤のコメントアウトを外した場合(try-catchで受け取る際に戻り値参照)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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> |
いかがでしたでしょうか。
JavaScriptのasync・await、特に例外処理は文法に少し癖があり、誤った記述をしても異常終了しないことがあるので、実際のシステム開発でも障害になりやすい所です。
awaitで待っていないように見える、例外発生時にだけ予期せぬ事象が出る、といった場合は、async・awaitの書き方が正しいか疑ってみましょう。
コメント