JavaScript:非同期処理②

非同期処理の流れ

下記のコードと図がとてもイメージしやすく、理解しやすい。

function taskA() {
   console.log("タスクAを実行 at " + Date.now());
}
function taskB() {
    console.log("タスクBを実行 at " + Date.now());
}
function taskAsync() {
    console.log("非同期のタスクを実行 at " + Date.now());
}

taskA();
setTimeout(() => {
    taskAsync();
}, 1000);
taskB();

非同期処理流れ

非同期処理の呼び出しでは、『非同期タスクを実行』するのではなく『非同期タスクを登録』する。

その観点を持っておくと、例外についても理解しやすい。登録時は処理は実行されないので登録する部分の処理に対して try...catch を書いてもキャッチできない。

キャッチするには、非同期処理のコールバックに書く必要がある。

// setTimeout は登録のみなのでそこでは例外は発生しない。
try {
setTimeout(() => {
        throw new Error("非同期的なエラー");
    }, 10);
} catch (error) {
    // よって、非同期エラーをキャッチできないので実行されない
}
console.log("この行は実行されます");

// setTimeout のコールバック関数の中なら、コールバック時に発生する例外をキャッチできる
setTimeout(() => {
    // 非同期処理の中
    try {
        throw new Error("エラー");
    } catch (error) {
        console.log("エラーをキャッチできる");
    }
}, 10);
console.log("この行は実行されます");

Async Function が返す Promise の種類

Async Function は必ず Promise を返すが、具体的には次の3つのケースがある。

  • Async Function が値を return した場合、その返り値を持つ Fulfilled な Promise を返す
  • Async Function が Promise を return した場合、その返り値の Promise を返す
  • Async Function 内で例外が発生した場合、そのエラーを持つ Rejected な Promise を返す

await 式はエラーを throw する

await 式の右辺の Promise が Rejected になった場合、エラーを throw する。Async Function 内で発生した例外は自動的にキャッチされるため、Async Function が Rejected な Promise を返すことになる。

await 式がエラーを throw するので、当該処理は tyr...catch にて例外を捕捉できるようになる。通常の非同期処理では、完了前に次の行が実行されてしまうため、 try...catch で捕まえられないので、.catch という形で捕捉していた。

参考