node.jsを勉強していて、callstackの問題にぶつかって、理解したことを書いていきます。
コード例
まず以下のコードを実行してみます。
1 2 |
console.log('Starting app'); console.log('Finishing app'); |
これはもちろん以下のような出力結果が得られます。
1 2 |
Starting app Finishing app |
では、以下のコードはどうでしょう?
1 2 3 4 5 |
console.log('Starting app'); setTimeout(() => { console.log('inside of timeout'); }, 2000); console.log('Finishing app'); |
setTimeout関数で、2000を指定。つまり、2秒後に内部の処理がなされるということです。
なので、以下のような出力結果になります。
1 2 3 |
Starting app Finishing app inside of timeout |
ここまではcallstackなどは考えずに、単純にコードを追うだけで処理を理解できるかと思います。
では次のコードは、どのような出力結果になるでしょうか?
1 2 3 4 5 6 7 8 9 10 11 |
console.log('Starting app'); setTimeout(() => { console.log('inside of timeout 1'); }, 2000); setTimeout(() => { console.log('inside of timeout 2'); }, 0) console.log('Finishing app'); |
setTimeout関数が2つ出てきます。
2つめのsetTimeout関数で、time指定が0に指定されているので0秒後、つまり、何も待たずに内部の処理が実行されます。
以下のような出力結果になります。
1 2 3 4 |
Starting app Finishing app inside of timeout 2 inside of timeout 1 |
あれ??
以下のような出力結果を予想したのではないでしょうか?
1 2 3 4 |
Starting app inside of timeput 2 Finishing app inside of timeout 1 |
ここで出てくるのがcallstackの概念です。
callbackの詳細をみていきましょう!
callstack(同期処理)
まず同期処理の例でcallstackを解説します。
以下のコードを実行します。
1 2 3 4 5 6 7 8 |
var add = (a, b) => { var total = a + b; return total; }; var result = add(2, 5); console.log(result); |
これは下図のように処理が行われています。
1.まず、main()関数が呼び出される。main関数は、ラッパー関数です。

2. add()関数がstackに積まれる。
呼び出されるまで内部の処理は実行されない。

3. result変数が定義される。

4. add()が呼び出される。

5. add()の内部処理がされる。


6. console.log()が処理される。

同期処理では以上のようにcallstackが使われます。
次は、非同期処理をみていきます。
callstack(非同期処理)
以下の図のように、callstackだけでなく、node APIs・Callback Queueという概念も出てきます。

では、先ほどのコード例で処理を追っていきましょう。
1 2 3 4 5 6 7 8 9 10 11 |
console.log('Starting app'); setTimeout(() => { console.log('inside of timeout 1'); }, 2000); setTimeout(() => { console.log('inside of timeout 2'); }, 0) console.log('Finishing app'); |
1. console.log(‘Starting app’)がcallstackに積まれる。

2. setTimeout(2000)をNode APIsで待機させる。
setTimeout関数はnode.jsのAPIなので、main()関数上で処理をせずに待機させる。
今回の場合は、2000の指定があるので2秒間待機する

3. setTimeout(0)をNode APIsで待機させる。

4. 0秒経過したので、setTimeout(0)をCallback Queueに積む。
0秒が経過数と、そのままcallbackを処理するのではなく、Queueに積んで、callbackを処理する順番待ちを行う。
Callback Queueに積まれたcallbackは、Event Loopで処理されるのだが、
Callstack上の処理が何もなくなったタイミングで、Queueから取り出されてcallbackが処理される。

5. console.log(‘Finishing app’);を実行する。

6. main()関数を閉じる。

7. callback(0)を実行

8. 2秒経過したので、setTimeout(2000)をQueueに積む。

9. setTimeout(2000)を実行

以上の処理順なので、以下のような出力結果になります。
1 2 3 4 |
Starting app Finishing app inside of timeout 2 inside of timeout 1 |
まとめ
nodeをマスターするにはまずcallstackなどの処理を理解しないとですね。
コメントを残す