【JavaScript】非同期処理の第一歩:コールバック関数を理解しよう
はじめに
時間のかかる処理はバックグラウンドで実行してもらうよう、非同期処理にして、完了したらコールバック関数を実行する、という解説をこれまで多く拝見されたと思います。
私もこれを見てなるほどと思いつつも、いざ自分で実装するとなった時に
- そもそも非同期処理ってどういう仕組みで動いているの?
- 関数の引数にアロー関数があるけどどういうこと?
という疑問を持ちました。
これらを調べていく中で、関数の引数としてコールバック関数を用いており、この点を理解することが非同期処理を理解する1つのポイントになるとわかりました。
この記事では、そもそもコールバック関数とは何かについて、できる限りわかりやすく解説していきます。
コールバック関数とは
コールバック関数とは、他の関数に引数として渡される関数です。
引数を受け取った側の関数の処理が優先され、その処理が完了した後に、渡されたコールバック関数が実行されます。
これだけだとイメージしづらいため、実際にコードを見ていきましょう。
// 指定した秒数が経過するとコールバック関数を実行
setTimeout(コールバック関数, 秒数)
setTimeout(function() {
console.log("2秒後に表示されるメッセージ");
}, 2000);
console.log("すぐに表示されるメッセージ");
本来、コードは上から順番に実行され、結果も上から順番に取得できます。
そのため、
2秒後に表示されるメッセージ
すぐに表示されるメッセージ
という順番で出力されそうですが、この場合このような順番では出力されず、以下の内容が出力されます。
すぐに表示されるメッセージ
2秒後に表示されるメッセージ
例のコードを紐解く
先ほどの解説で、「引数を受け取った側の関数の処理が優先され、その処理が完了した後に、渡されたコールバック関数が実行されます」と解説しました。
引数を受け取った側の関数: setTimeout()
コールバック関数: function() {console.log("2秒後に表示されるメッセージ");}
という関係になります。
つまり、setTimeout() の処理が完了すると、function()...で定義した処理が実行されます。
では、「setTimeout() の処理」とは何か?
これは、指定した秒数後にコールバック関数を実行するタイマーを設定することを意味します。
このタイマー設定自体は即座に完了します。
そして、タイマーが完了した(指定した秒数が経過した)ときに、コールバック関数が実行されるのです。
したがって、setTimeout()が引数で指定した秒数を設定すると処理が完了し、指定秒数後にコールバック関数が実行されるということになります。
処理の流れを一般化
コールバック関数の流れをより一般化してまとめると以下のようになります。
親関数(引数, コールバック関数)
1. 親関数の呼び出し
親関数(引数, コールバック関数)を呼び出します。
2. 親関数の実行
親関数は、まず自身の内部にある処理を開始します。
この処理は、ファイルの読み込み、APIからのデータ取得など、時間がかかる可能性のあるタスクです。
3. 完了後の実行
親関数の処理が完了したとき、親関数は引数として受け取ったコールバック関数を呼び出し、その処理を実行します。
この仕組みにより、親関数は自身のタスクに集中し、その結果の処理はコールバック関数に任せることができます。
まとめ
コールバック関数は何かの関数の引数として渡すことがお分かりいただけたと思います。
引数として渡された側の関数は本来の自分の処理に集中し、その処理が完了した時にコールバック関数を実行するという流れが理解できれば、非同期処理を理解する上での重要なポイントの1つを攻略したと言えるでしょう。
コールバック関数は非同期処理を可能にしますが、複数の非同期処理を連続して実行する場合、関数が深くネスト(入れ子)になり、コードが読みにくくなる『コールバック地獄』という問題を引き起こすことがあります。
Promiseオブジェクトやasync/awaitといった仕組みは、この問題を解決するために生まれました。
非同期処理を理解するためには、Promiseオブジェクトなど他の要素も押さえる必要がありますが、
まずはその第一歩として今回、コールバック関数について基本的な動作について解説させていただきました。
最後までお読みいただき、ありがとうございました。
参考URL
Discussion