# JavaScript — Heap, Stack, Event-loops and Callback Queue
* 網頁的運行
* 名詞解說
* 實際測試:分解程式碼
* 關於setTimeout的毫秒數
##
### 網頁的運行
簡單提及網頁的運行方式,
其中最重要的是關於JavaScript的兩種特性,分別為單線程語言(single thread)和同步執行(synchronous)。
這兩種特性說明了Javascript的運行環境會由上到下的執行程式,並且一次只處理一件事,做完一件事才接著做下一件。
>那這樣我們的網頁是如何處理繁複的資料與程式,並呈現到網頁上的呢?
因為瀏覽器不僅僅只有Javascript的運行環境,它提供了許多webAPIs,我們會透過程式的呼叫來做運用,舉例來說,像是常見的`setTimeout`,`ajax(XMLHttprequest)`,當瀏覽器接收到這些代碼時,就會被移動到webAPIs執行,而不會阻擋到主程式。也就是達到非同步執行程式(asynchronous)的效果。
>所以說這個非同步實際上是如何被運行的呢?讓我們接著看下去 ...
### 名詞解說
<font color=red>`Heap`</font>:是一個拿來存放程式中已宣告之變數、函式等的空間。
<font color=red>`Stack`</font>:程式中要執行之函式跳進去的地方,執行完即跳出,具有後進先出(Last in First out)的性質。
<font color=red>`WebAPIs`</font>:當要執行非同步程式時,瀏覽器會在這邊開始執行,不會影響到主程式,執行完畢後不會直接被送到Stack,而是被送到callback Queue排隊等待。
<font color=red>`Callback Queue / Task Queue`</font>:是儲放非同步程式執行完成的空間,等待被丟進Stack執行。
<font color=red>`Event Loop`</font>:Event Loop 會持續查看 Stack 是否都執行完空下來了,如果是的話就會把 Callback Queue 裡面的任務依序丟進 Stack 去做執行。
將以上的流程以圖像化呈現,大致上是這樣子的

##
### 實際測試:分解程式碼
這邊以一段簡短的程式碼作為實例

程式執行的結果會是

>這五秒間背後的程式是如何被運作的呢?這裡我使用[Loupe](http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)視覺化工具進行說明。
<br/>
1.首先會執行`console.log("Hi There.")`。

2.瀏覽器偵測到`setTimeout`,於是將它移動到webAPIs做執行,主程式繼續往下執行。

3.執行`console.log("Hello again.")`。

4.五秒過後setTimeout執行完成,移動至Callback Queue 裡等待傳喚

5.Event Loop發現Stack裡任務皆被清空,會呼叫Callback Queue裡面的任務丟進Stack裡,執行`console.log("passed 5 sec.")`。

[點擊這裡可以看在Loupe上執行的效果](http://latentflip.com/loupe/?code=Y29uc29sZS5sb2coIkhpIFRoZXJlLiIpCgpzZXRUaW1lb3V0IChmdW5jdGlvbiBjYWxsYmFjaygpewogICAgY29uc29sZS5sb2coInBhc3NlZCA1IHNlYy4iKQp9LDUwMDApCgpjb25zb2xlLmxvZygiSGVsbG8gYWdhaW4uIik%3D!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)
將流程視覺化後可以顯而易見的了解到,當程序中出現非同步程式時會被隔離到webAPIs執行,就不會擋住主程式,避免掉同步執行時會有的阻塞(block)現象。經過圖像化的說明後,是不是變得比較好理解了呢?
### 關於setTimeout的毫秒數
另外`settimeout`裡面所設定的毫秒數只能代表他==至少==需要多少時間,就像前面所說的,程式執行完成後會進到`Callback queue`等待`EventLoop`偵測當前`Stack`是否為空,才會依序做執行。
假如今天有一段代碼如下:

執行後的結果會是這樣

由此可說明setTimeout只能確保幾毫秒過後程式==即將==會被執行,並不表示幾毫秒過後它會即刻被執行。
[點擊這裡可以看在Loupe上執行的效果](http://latentflip.com/loupe/?code=c2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coJzFzZWMgbGF0ZXI%2FJykKfSwgMTAwMCkKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coJzFzZWMgbGF0ZXI%2FJykKfSwgMTAwMCkKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coJzFzZWMgbGF0ZXI%2FJykKfSwgMTAwMCkKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coJzFzZWMgbGF0ZXI%2FJykKfSwgMTAwMCk%3D!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)
##
### 參考資料
[MDN-webAPIs](https://developer.mozilla.org/zh-TW/docs/Web/API)
[Philip Roberts: What the heck is the event loop anyway?](https://www.youtube.com/watch?v=8aGhZQkoFbQ&ab_channel=JSConf)
[JavaScript、React、Flask、MongoDB 網站全端開發:從入門到進階](https://www.udemy.com/course/javascript-es6-react-redux/)