---
# System prepended metadata

title: '[JS 筆記] event loop'
tags: [面試問題集, JS筆記]

---

# [JS 筆記] event loop

### 單執行緒(single Thread)
Javascript(以下簡稱JS) 是一種單執行緒(single Thread)，指的是JS一次只能執行做一件事，或是同一時間只能執行一段程式碼(一行一行執行)。


### 呼叫推疊(Call Stack)
而當程式執行時，怎麼確定執行順序?
Call Stack會記錄目前程式執行的位置，如果執行到一個函式(function)，會將函式pop in Stack 中，等函式執行結束，才會將其pop out Stack。參考 [Call Stack動畫介紹](https://www.youtube.com/watch?v=Q2sFmqvpBe0)，可以特別注意到Stack採用FILO(First In Last Out)；而待會也會介紹到的Queue是FIFO。


---


### 阻塞(Blocking)
因此，當程式碼一多，且Call Stack 必須一層層執行，當上層任務沒結束前，下層任務則無法開始，可想而知，若沒有安排好或是解決方式，勢必會塞車，這種狀況，稱阻塞(Blocking)。若是在前端，配合UI/UX時，網頁畫面則會產生更明顯的資料不同步，和延遲的狀況，而造成使用者體驗差。


### 非同步回呼(Asynchronous Callback)

為了避免程式碼發生阻塞，最常見的處理方式，就是非同步回呼(Asynchronous Callback)。

```
console.log('Hi')

setTimeout(function cb() {
  console.log('There')
}, 5000)

console.log('JSConfEU')
```
可以將他SOP，整理成

1. 若同步的動作則直接執行
1. 非同步的動作則丟到 Web Apis 做處理
1. 若 function 內有另一個 function 則向上堆疊( Stack )
1. 執行完成後則移出 Call Stack

當我們在瀏覽器中輸入會發現，Hi JSConfEU很快就印出來了，過了5秒後There才印出，將程式碼切細，分成:
1. 印出Hi
2. 執行setTimeout，傳到 WebAPIs準備5秒等待時間到
3. 印出JSConfEU
4. 5秒時間到，傳至Callback Queue
5. 傳回至Stack
6. 印出There


### 瀏覽器內的執行

> 為甚麼JS是單執行緒，卻沒有依序印出?
> 甚麼是WebAPIs、Callback Queue?

JS的確只能執行單執行緒，但可以一起做很多事，而不是僅提供一個運行環境，瀏覽器還提供很多WebAPI，常見的如:document、XMLHttpRequest、setTimeout...給我們使用，但由於他們不在V8引擎中，只能以呼叫方式去執行這些功能。因此，當瀏覽器知道你要呼叫他們來用的時候，就可以和你的程式碼同時一起執行 (Concurrency) ，也不會影響到你的 JS 主程式。

![](https://i.imgur.com/DuBMHN5.png)

整個流程如上，
* Heap：程式中宣告、定義變數、函式…等的記憶體位置
* Stack：程式中要執行的函式 pop in 的地方，一次執行一個，完成後 pop out。
* WebAPIs：當要執行的程式為非同步 WebAPIs，瀏覽器即會和程式一起開始執行，當他執行完，也不會把結果隨便丟回你的程式中，他會去排進 Callback Queue 中。
* Callback Queue / Task Queue：這裡就是儲放 callback function 的地方，等著被丟進 Stack 被執行。
* Event Loop：Event Loop 會持續查看 Stack 空下來了沒有，如果已經空了，就把 Callback Queue 裡面的任務丟進 Stack 讓他去執行。

了解以上流程後，再看一個例子

```
function A() {
  console.log("functionA");
  setTimeout(() => console.log("setTimeout1"), 2000);
  B();
}
function B() {
  console.log("functionB");
  setTimeout(() => console.log("setTimeout2"), 1000);
}

console.log("start");
A();
console.log("end");
```
實際看一下 Demo 來了解運作，以上分別有 A、B 兩個函式，內部分別還有一個 setTimeout，而 A 函式會呼叫 B 函式，讓我們來看看 console.log 出來的順序

```
start
functionA
functionB
end
setTimeout2
setTimeout1
```
大概流程如下：

* 將 console.log("start") 丟入 Call Stack 執行，完成後移出
* 將 A 函式丟入 Call Stack 執行
* 將 console.log("functionA") 丟入 Call Stack 執行，完成後移出
* 將 setTimeout1 丟到 Web Apis 執行
* 將 B 函式丟入 Call Stack 執行
* 將 console.log("functionB") 丟入 Call Stack 執行，完成後移出
* 將 setTimeout2 丟到 Web Apis 執行
* B 函式執行完成，移出 Call Stack
* A 函式執行完成，移出 Call Stack
* 將 console.log("end") 丟入 Call Stack 執行，完成後移出
* 經過一秒後 setTimeout2 執行完成，並將 callback 放入 Callback Queue
* Call Stack 為空，將 Callback Queue 內的 setTimeout2 callback 放入 Call Stack 執行
* console.log("setTimeout2") 執行完畢後移出
* 經過兩秒後 setTimeout1 執行完成，並將 callback 放入 Callback Queue
* Call Stack 為空，將 Callback Queue 內的 setTimeout1 callback 放入 Call Stack 執行
* console.log("setTimeout1") 執行完畢後移出



---


### 參考
* [所以說event loop到底是什麼玩意兒？| Philip Roberts | JSConf EU ](https://www.youtube.com/watch?v=8aGhZQkoFbQ)

* [JavaScript - Event Loop](https://ithelp.ithome.com.tw/articles/10230871)


### 補充
* [[JavaScript] Javascript 的事件循環 (Event Loop)、事件佇列 (Event Queue)、事件堆疊 (Call Stack)：排隊](https://medium.com/itsems-frontend/javascript-event-loop-event-queue-call-stack-74a02fed5625)

* [Day 11 [EventLoop 01] 一次弄懂Event Loop（徹底解決此類面試問題）](https://ithelp.ithome.com.tw/articles/10241081)


###### tags: `JS筆記` `面試問題集`
