One minute
What Is Event Loop?
究竟什麼是 event loop?
Event loop 就字面上的意思來解釋就是「事件圈」。用我的理解來說就是事件的發生順序。但在 JavaScript 中,事件的發生順序卻與我們所以為的有那麼一點不同。而這也就是這篇筆記的主旨,讓我們來好好來了解究竟 event loop 是如何發生在 JavaScript 執行程序中的。進入正題之前,先來認識幾個有點陌生的單字。
名詞解釋
單執行緒(Single-Threaded)
JavaScript 是單執行緒的程式語言,白話來說就是由上而下一行一行地執行、一次只做一件事。
堆疊區(Stack)
JavaScript 引擎會將執行的程式放到堆疊區(Stack)中,代表他目前正處理到哪個段落。如下圖所示,JavaScript 引擎將任務先放到堆疊區(Stack)中,然後一行一行地執行。而碰到 return 時,就直接脫離堆疊。

事件佇列(Task Queue, Callback Queue)
有一些無法預期什麼時候會被執行的操作,像是 setTimeout、event 監聽器、Ajax,在 JavaScript 中都會以非同步的方式被處理。也就是先被放到事件佇列,等到同步執行的程式碼執行完,再回過頭來處理那些被放到佇列中的任務。

所以,到底什麼是 event loop?
JavaScript 在執行程式的順序是這樣的:
- 將函式放到堆疊區(Stack)中
- 如果有非同步的處理程式,例如上述的 setTimeout、event 監聽器、Ajax,會先被放到事件佇列(Callback Queue)
- 在堆疊區(Stack)中的一般函式被執行
- 等到堆疊區(Stack)中執行完畢後,再將事件佇列(Callback Queue)中等待執行的任務丟到堆疊區(Stack)中
- 執行完堆疊區(Stack)中的任務後,再回到事件佇列(Callback Queue)查看是否還有任務要做
這個過程就是 event loop! 第 4 步驟是我們下一步解題的關鍵,多閱讀幾次,放到你心中。
拆解 setTimeout 函式的謎題
用範例會更好理解,首先我們輸入:
setTimeout(function() {console.log('delay 0 sec')}, 0)
console.log('Hello!')
得到這樣的結果:
Hello!
delay 0 sec
可以發現 Hello! 比起設置了 0 秒的 setTimeout 函式更早出現,為什麼呢?讓我們套用上述的流程,就可以一覽無遺。
setTimeout函式被放入堆疊區(Stack)中- 由於
setTimeout屬於非同步處理程式,因此在堆疊區(Stack)中跑完設定的時間後,會被移到事件佇列(Callback Queue)待機 console.log('Hello!')被放入堆疊區(Stack)中- 堆疊區(Stack)中的
console.log('Hello!')被執行 - 印出
console.log('Hello!')結果 - 此時,堆疊區(Stack)已經沒有任何任務,將
setTimeout從事件佇列(Callback Queue)中拿出來執行 - 印出
setTimeout結果
由上面的過程,我們可以推論「setTimeout 設定的等待時間,其實並不能保證它會在設定的時間一到就被執行,JavaScript 引擎要先確定堆疊區(Stack)中的任務都執行完後,才會再回過頭來處理事件佇列(Callback Queue)中的任務。假設我們設定時間為 0sec,只能說它會在大於等於 0sec 後才會執行。」
參考資料
What the heck is the event loop anyway? | Philip Roberts | JSConf EU > [筆記] 理解 JavaScript 中的事件循環、堆疊、佇列和併發模式(Learn event loop, stack, queue, and concurrency mode of JavaScript in depth) > Understanding Event Loop, Call Stack, Event & Job Queue in Javascript > What are Event Loops and What Does It Have to Do with JavaScript? > 單執行緒&非同步發生的血案
2020-11-23 22:29