はじめまして!!ノベルワークス入社2年目のそうまです!!!
今回は javascript
で中々見えづらいデータの動きを関数に着目して調査したので、ノートとして残そうと思います!!
調査のきっかけ
直近でデータ移行の業務に携わる機会がありました。この業務では、大量のデータを効率よく処理するために、メモリを意識したコードを書く必要がありました。しかし、普段は JavaScript
しか触っておらず、メモリを意識する機会が無いため「メモリ割当って何??」という基本的な状態から学び直す必要がありました。
何故メモリを意識しなくて良いか
javascript
等の高級言語はほぼ一様にガベージコレクションを搭載しており、メモリの割り当て・解放を自動的に行ってくれるため。
そのとき、「JavaScript Visualizer 9000」というWebサービスに出会いました。このツールは、関数がスタックやキューにどのように出し入れされているかを視覚的に確認できるものです。「まずはこれを使えば、関数のメモリ割り当てや解放の流れを掴むための参考になるかも!」と思い、早速試してみることにしました!
関数実行の流れ
早速ですが以下のようなコードがあったとします、関数がどの順番でコールスタックに追加され、その後削除されるかを考えてみましょう。 javascript
のコードの実行順基づいて考えると理解しやすいかもしれません!
コールスタック
どの関数が現在実行されていて、その関数の中でどの関数が呼び出されたかを追跡するための仕組み。
function a(){}
function b(){}
function c(){}
a()
b()
c()
このコードでは、以下の順番で関数がコールスタックに追加され、削除されます!
-
a
関数がコールスタックに追加 → 実行後に削除 -
b
関数がコールスタックに追加 → 実行後に削除 -
c
関数がコールスタックに追加 → 実行後に削除
では、次の例ではどうなるでしょうか?
function a(){}
function b(){ a() }
function c(){ b() }
c()
この場合は以下のようになります!
この場合、関数がネストして呼び出されるため、以下のようにコールスタックが変化します!
-
c
関数がコールスタックに追加 →b
関数を呼び出す -
b
関数がコールスタックに追加 →a
関数を呼び出す -
a
関数がコールスタックに追加 → 実行後に削除 -
b
関数を削除 → 最後にc
関数を削除
setTimeout
関数 と タスクキュー
この2つの関数は特殊で、指定したミリ秒後にコールバック関数の実行します、では以下のようなコードがあったとして"指定したミリ秒" の間どのように実行を待つのでしょうか?
setTimeout(function a(){}, 1000)
正解は「タスクキュー」に格納され、実行を待つ事になります!
キュー
javasctiptにおけるキューは、処理に紐づいているメッセージをリストとして持っており、必要な時キューからメッセージが取り出され実行される仕組みになっている。
タスクキュー内では、メインスレッドの処理が完了した後にコールバック関数が実行されます!
then
と catch
then
やcatch
といった関数は、Promise
の状態がpending
から解消(fulfilledまたはrejected)された後に実行されます。この際、setTimeout
関数と同様に待ち時間が発生しますが、格納されるキューが異なり、これを「マイクロタスクキュー」と呼びます。
こちらPromise
に関しては、Promise.resolve()
のような直ぐにPromise
を返す「マイクロタスク」と、fetch
のように非同期処理の結果を待って解決される「マクロタスク」に依存するものがあります。それぞれキューに格納されるタイミングが異なり非常にややこしいのでこれに関しては別で記事にしようと思います!!
纏め
今回はJavaScript
における関数がいつ実行されるのか大体の流れを掴む事が出来ました!特にコールスタックやタスクキューの動作を理解することで、JavaScriptのコード実行順序をより深く理解出来たように思えます!
次回はPromise
を返す「マイクロタスク」がどのような仕組みで動き、キューへと格納されるのかを調査したいとおもいます!!