はじめに
今まで特に意識せずにAPIコールしていたのですが、JavaScriptのFetch APIを使うことになり、いざ書いてみるとasyncやawait、Promiseなどの非同期処理がわかっていないことに気づいたので、整理しようと思いました。
まだ理解や解釈が曖昧なところがあるため、間違っているところなどありましたら教えてくださると嬉しいです🙇
参考
JavaScriptはシングルスレッド
まずはJavaSctriptがどのようにプログラムを実行しているのかを知る必要があります。
JavaScriptでは、プログラムの実行はシングルスレッドで行われます。
プログラムを実行しているのが1人しかいないイメージです。コードを順番に処理していきます。複数の処理を同時に行うことはできません。
非同期処理とは
では非同期処理とはなんでしょうか。
非同期処理はコードを順番に処理していきますが、ひとつの非同期処理が終わるのを待たずに次の処理を評価します。 つまり、非同期処理では同時に実行している処理が複数あります。
時間がかかる処理があった時に、それが終わるのを待たずに他の処理を進めておいて、終わったら合流するようなイメージです。
先輩がとても良い例えを教えてくれたのですが、「コードのレビューを依頼して、レビューが返ってくるのを待っている間、何もしないで待っているのではなく、他のタスクを進めておいて、レビューが返ってきたらそのタスクに戻る」という例えがとてもしっくりきました。
ここで疑問が1つ。
シングルスレッドなのになぜ非同期処理では複数の処理を同時に実行できるの??🤔
最初の説明と矛盾していますよね。
少し調べてみたのですが、イベントループという仕組みによって実現できているらしいです。
残念ながら難しくて理解できなかったのですが、多分JavaScriptにはコールスタックとタスクキューというものが備わっていて、現在実行中のタスクはコールスタックに積まれていきます。非同期処理の場合はタスクキューに積まれて、コールスタックが空になり次第実行される、みたいな感じらしいです。
やはり、先輩が教えてれた例えがかなり正確なイメージな気がしました。
- コードレビューを依頼する=>レビューが返ってきたらタスクキューに積まれる
- レビューを待っている間他のタスクを進める=>コールスタックに積まれたタスクを実行
- キリが良くなったタイミングで返ってきたレビューを確認する=>コールスタックに積まれたタスクが空になり次第、タスクキューに積まれたタスクを実行
この解釈が合っているかどうか、もっと良い例え、説明がありましたら教えてください🙇
実務でよく使われる非同期処理はAPIコールです。
時間がかかる処理なので処理が完了するのを待っていたら、表示が更新されない時間が数秒続く…なんてことが起きる可能性があります。
非同期処理と例外処理
非同期処理では、try...catch構文
を使っても非同期的に発生した例外をキャッチできません。
try...catch構文がよくわかっていなかったので復習すると、例外(エラー)が起こる可能性があるときに使って、エラーが起きた時にどうするかを書きます。
try {
throw new Error("同期的なエラー");
} catch (error) {
console.log("同期的なエラーをキャッチできる");
}
console.log("この行は実行されます");
ここで注意点があります。
try句{}
の中で発生した例外をキャッチする構文であるため、外で発生したエラーは感知できません。
そのため、非同期処理の例外をキャッチしたい場合は、非同期処理のコールバック関数の中にtry...catch構文を書いてエラーを感知できるようにします。
// 非同期処理の外
setTimeout(() => {
// 非同期処理の中
try {
throw new Error("エラー");
} catch (error) {
console.log("エラーをキャッチできる");
}
}, 10);
console.log("この行は実行されます");
しかし、非同期処理の中で例外が出たとしても、非同期処理の外はそれを感知できないので、最後の行が実行されてしまいます。
APIコールはエラー出る可能性高いですよね。なんとかして、エラーをキャッチして非同期処理の外に伝えなくてはなりません。
この非同期処理において例外を扱うために重要なのが、Promise
とasync
です。
いや難しすぎる!!!!
続きは明日書きます。