【JavaScript 】Event Loop到底如何運行

Tina
6 min readApr 9, 2021

--

基礎又艱深的用詞single thread / call stack / blocking / queue / event loop / setTimeOut 看影片學起來!

學過JS相信一定有聽過Event Loop,這邊記錄下我觀看所以說event loop到底是什麼玩意兒?| Philip Roberts | JSConf EU 這部影片的心得筆記,順便也將裡面提到的內容再做多一點延伸,一開始先針對Event loop會遇到的一些名詞作解釋

single thread(單一線程):

JavaScript是single thread language,代表的是只有一個call stack 和一個 memory heap,同時也表示他會執行完一段程式碼後再接續執行下一段程式碼(一次做一件事情)。

Call Stack(Last In, First Out)

是一種資料結構,紀錄依序堆疊尚未執行的程式碼,第一個被呼叫的會被放在底層,最後被呼叫的被放在頂層,並開始執行,因為他的LIFO特型,頂層的會先被執行,再依序往下執行。

如以下流程:

  1. 呼叫 eating() 函式
  2. 將 eating() 函式加入 Call Stack 中
  3. 進入 eating() 函式中的 eatLunch()
  4. 將 eatLunch() 放入 Call Stack 中(會放在 eating() 函式之上,因為LIFO)
  5. 開始執行最後放入的函式,也就是 eatLunch() ,並印出 pizza!
  6. 執行完 eatLunch()後,從 Call Stack 中移除,此時 Call Stack中剩下 eating()
  7. 往下執行完 eating() ,結束後同時從 Call Stack 中移除,此時 Call Stack 為空,可以接下去進行下一個動作了!
From MDN: https://developer.mozilla.org/en-US/docs/Glossary/Call_stack

blocking阻塞

需要花時間完成的程式(如網路請求),且因JS是single thread,所以當這些速度較慢的request尚未執行完成時,主程式不能往下走,且不能執行其他操作,若想要有流暢的UI的話,這是不能發生的情形。

WebAPIs

JavaScript runtime一次只能做一件事情沒錯,但瀏覽器會提供許多APIs讓我們可以同時執行任務,並將透過APIs完成的任務放進Queue中,像是DOM、ajax 和本次主角setTimeOut。

callback queue / task queue( FIFO = First In, First Out)

暫存從WebAPIs傳送來的任務,等待event loop的調配,當call stack清空後,就會將callback queue 的任務依序傳送至call stack

這時候就要講到本次的重點了,JavaScript 、 callback queue、WebAPIs 與event loop的關係

event loop

查看stack 並查看task queue,如果stack是空的(一定要等到是清空的才可以往下執行),他會將task queue的第一個東西丟到stack上,並讓stack可以順利執行。

以下進行簡單的說明

1.從 js 中開始進行程式,並從第一行開始執行,放入stack中,再console出來

2.來到setTimeOut部分,一樣先放置stack中,接著瀏覽器就啟動計時器,同時表示呼叫setTimeOut完成,就把setTimeOut從 stack中移除。

3.此時stack是空的, js 就繼續往下執行console.log並印出JSConfEU,而此同時WebAPIs依舊在進行。

4.與此同時,WebAPIs的五秒也到了,但 WebAPIs 不能隨便將完成好的程式丟回stack中,這樣會導致整個程式碼的執行順序錯亂,所以基本上跑完任何 WebAPIs 後,都會將call back傳送至 callback quene中等待傳送。

5.此時就是Event loop的工作了,他確認stack沒有任何待執行程式後,就會將第一個送入callback queue的callback,傳送至stack中,也就是我們的function cb(),接下來再執行function cb()中的程式,也就是印出there。

6.執行完印出there整個function cb()就結束了,最後stack也被清空,從這邊也能看到,透過WebAPIs的協助,JS不用等到執行完setTimeOut才往下執行,而是同步進行的。

這時候可能會有人很好奇,那如果把setTimeOut的時間改為0秒呢?會不會console出來的順序是there在中間,答案是不會的!

因為不論你setTimeOut的時間設置多少,他一樣會經過WebAPIs再到callback queue中等待stack被清空,因此結果會是一樣的,以下我直接執行程式來示範,若還有疑問歡迎提出唷!

setTimeOut設置5秒
setTimeOut設置0秒

以下直接放神影片連結,裡面的動畫+模擬器真的很幫助了解整個原理!

--

--

Tina
Tina

Written by Tina

前端工程師 Mix 數位行銷人

No responses yet