tryブロックの中から呼び出した関数内で例外が発生した場合

try...catch 文を使った例外処理は、 try ブロック内に記述された文で例外がスローされた場合に例外をキャッチして処理を実行するものですが、 try 文の中から呼び出した関数の中で例外が発生した場合でも例外をキャッチすることができます。ただ、コールバック関数を使用する場合には注意が必要です。ここでは try ブロックの中から呼び出した関数内で例外が発生した場合の扱いについて解説します。

(Last modified: )

tryブロックの中から呼び出した関数内で例外が発生した場合

try...catch 文の書式は次のようになっており、例外が発生する可能性がある文を try のあとのブロック内に記述しておく必要があります。

try{
  例外が発生する可能性がある文を記述
  ・・・
} catch(e) {
  例外をキャッチしたときに実行される処理
  ・・・
}

それでは try ブロックの中で try...catch 文の外に記述された関数を呼びだし、その関数内で例外がスローされた場合はどうなるのでしょうか。

function func(){
  // ここで例外が発生
}

try{
  func();
} catch(e) {
  例外をキャッチしたときに実行される処理
  ・・・
}

このような場合でも try ブロック内で例外がスローされた場合と同じく例外をキャッチして catch のあとのブロック内の処理を事項します。

次のサンプルをみてください。

function sum(a, b){
  let sum;
  sum = a + b;

  return sum;
}

console.log('Start');

try{
  console.log(sum(10, 8));
  console.log(sum(10, 8n));
} catch(e) {
  console.error(e);
}

console.log('End');

>> Start
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> End

今回のサンプルでは例外が発生する可能性のある関数を try ブロック内に記述するのではなく、関数を呼びだす文を try ブロックの中に記述しています。呼びだした関数は try ブロック内には記述されていませんが、このようなケースであっても関数がスローした例外を関数の呼び出し側でキャッチして処理することができます。

もう一つサンプルをみてください。

function sumB(a, b){
  let sum;
  sum = a + b;

  return sum;
}

function sumA(a, b){
  return sumB(a, b);
}

console.log('Start');

try{
  console.log(sumA(10, 8));
  console.log(sumA(10, 8n));
} catch(e) {
  console.error(e);
}

console.log('End');

>> Start
>> 18
>> TypeError: Cannot mix BigInt and other types, use explicit conversions
>> End

先ほどのサンプルを少し修正し、間にもう一つ関数をはさみました。このような場合であっても最終的に呼び出された関数でスローされた例外は、呼び出し元を順にさかのぼっていき、いずれかのところで try...catch 文を使って例外をキャッチできれば例外に対する処理を行うことができます。

非同期処理のコールバック関数で例外が発生した場合

呼びだした関数内で発生した例外は、関数を呼びだした側でキャッチできるという点は先ほど解説しましたが、注意点もあります。それは非同期処理を行うコールバック関数の中で発生した例外はキャッチすることができないという点です。

次のサンプルをみてください。 setTimeout 関数を使って指定した時間が経過したら引数に指定したコールバック関数を呼びだす簡単なプログラムです。

console.log('Start');

setTimeout(function sum(a, b){
  let sum = a + b;
  console.log(sum);
},1000, 10, 8);

console.log('End');

>> Start
>> End

>> 18

setTimeout 関数の 2 番目の引数に 1000 ミリ秒( 1 秒)を指定しているので、 setTimeout メソッドが実行されて 1 秒経過すると 1 番目の引数に指定したコールバック関数が呼び出され演算結果がコンソールに出力されます。

このコールバック関数内で例外が発生する可能性があるので、 setTimeout 関数の部分を try ブロック内に記述し、そしてコールバック関数に渡す引数の値を数日と長整数に変更して試してみます。

console.log('Start');

try{
  setTimeout(function sum(a, b){
    let sum = a + b;
    console.log(sum);
  },1000, 10, 8n);
} catch(e) {
  console.error('例外をキャッチしました');
}

console.log('End');

>> Start
>> End

>> Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

このサンプルを実行してみると、コールバック関数内で発生した例外は try...catch 文でキャッチすることができずにエラーをコンソールに出力してプログラムが強制終了してしまいました。これはコールバック関数は try ブロック内にあってもコールバック関数を呼びだしているのは try ブロックの外からだからです。

このように非同期処理でコールバック関数を利用する場合に、コールバック関数内で発生した例外についてはキャッチすることができませんのでご注意ください。

-- --

try ブロックの中から呼び出した関数内で例外が発生した場合の扱いについて解説しました。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。