close

大家在寫程式的時候,應該都會知道先寫的東西會先執行,
先寫出來要電腦印出來的東西,也理所當然會先印出來,
但是怪了??以下這個狀況卻不一樣!!
「hello」明明寫在最後面,卻先印出來了??

image

原來這都是因為JavaScript的事件迴圈(Event Loop)機制的原因!

在看了很多資料後,才終於稍微比較了解Event Loop是什麼樣的內容,
把它擬人化理解的話,Event Loop就是決定任務執行順序的管理者,
但是為什麼需要有個管理者來管理JavaScript的任務執行順序呢?

讓我們先來看看JavaScript的特性吧!
 

JavaScript的特性
JavaScipt在執行時,一次只會執行一個任務,屬於單執行緒(single thread)。
這個部分,可把它想像成有一間餐廳只有一個位置,一次只能接一位客人的單,
所以從客人點單、到做餐點、送餐、結帳這些過程全部都完成後,
才可以接下一位客人(任務)。
聽起來好像有點笨XD,但是JavaScript的特性就是如此,
所以就需要透過Event Loop讓JavaScript能夠順利在多執行緒的瀏覽器環境下執行。

在正式進入了解Event Loop機制的環節前,再來理解一些相關的名詞。
 

Event Loop機制相關名詞
堆疊 Stack
顧名思義就是從下往上堆的一疊東西,最些拿到的東西會放在最底層,
最後拿到的東西反而會在最上層,所以是「先進後出」。
以圖像來呈現的話,就會像下面這張圖一樣,1號方格雖然是最先堆上去的方格,
但是會最後才被拿出來。

image
 

佇列 Queue
佇列的話,則是一個從左排到右的對列,就像人在排隊一樣,
先排進對列的東西,就會先被拿出來,所以是「先進先出」。
以圖像來呈現的話,就會像下面這張圖一樣,1號方格先排進去,所以會先被取出。

image
 

Event Loop機制為何?
認識相關的名詞後,我們就直接進入正題了解Event Loop機制吧!
簡單來說的話,Event Loop機制會依序不斷地進行以下兩個確認步驟。

image

步驟1:檢查Stack裡面有沒有東西,有東西就會先執行Stack的東西到Stack裡面的東西被清空。
步驟2:確認Stack裡面都沒有東西後,才會檢查Queue裡面有沒有東西,有東西的話,
會把一個東西推移到Stack,才會執行最後流程。這裡等於是回到了第1個步驟,跑完完整的執行流程後,
才會再回到第2個步驟確認Queue是否還有東西。

*第二個步驟一次只會將Queue裡面的一個東西放到Stack裡面,等到完全結束後,
才會再次把Queue的另一個東西放到Stack,以此類推。

到這個部分,我自己還算能理解,而我自己理解到的總結就是「Stack裡面的任務會先完成,跑到Queue的任務則是最後完成」。

可是又有一個問題出現了!
那就是到底什麼樣的任務會被放到stack?什麼樣的任務被放到Queue呢?

 

哪些任務會跑到Queue?
其實不管什麼樣的任務其實都會先被放入Stack,但有某部分的任務,
卻會在放到Stack之後,又跑到了Queue,最後才再次回到了Stack,
也才跑有辦法完整個執行流程。那到底是哪些任務會跑這樣的流程呢?

答案就是「存在於瀏覽器中,但不存在於JavaScript引擎內的API」
像是計時類型的API(例如一開始出現的setTimeout)、操作DOM節點的API、AJAX有關的API。

不過這些任務並不是直接從Stack移動到Queue,而是會經歷以下的過程。
因為這些API不存在於JavaScript引擎內,所以必須調用瀏覽器提供的API才能順利進行,
流程就會變成Stack->web APIs->Queue->Stack(執行完成)


也就是說跑到Queue之前,其實還會經歷在瀏覽器環境中執行API的過程。

實際案例
最後讓我們用一開始的那部分程式碼,來理解這個機制的運作流程吧!
image
在這個情況下,其實程式碼背後運作的流程會變成下面這個樣子。
1. 主程式碼main()先跑進Stack區 (也就是這一整個完整的程式碼本身)

image
2. setTimeout接著進入Stack區
image
3. 接著進入webAPIs執行計時的內容
imageimage
4. 計時完成後,進入Queue
imageimage
5. hello進入Stack,印出Hello,消失在Stack中
imageimage
image
6. 因為hello這部分也執行了,所以main也等於完全執行,所以消失在Stack中
image
7. 因為現在Stack這一區已經空了,所以最後被推送到Queue的setTimeout,會再次送回Stack
image

8. 印出'delay 0 sec'之後,Stack就全部清空
image
image
這也是為什麼'delay 0 sec'會在最後才被印出來的原因。
 

結論
因為需要透過瀏覽器執行動作的任務,會在webAPI區執行後,
再回到Queue等待Stack區的所有任務完成,才會移動到Stack執行,
所以會是最晚執行的內容,也是因為這樣setTimeout這個內容不管設定倒數幾秒,
都會是後面才執行的內容。

以上就是這次的學習筆記!
如果有不正確的理解內容,也歡迎大家告訴我喔!

 

arrow
arrow
    創作者介紹
    創作者 文科少女寫程式 的頭像
    文科少女寫程式

    文科少女學程式

    文科少女寫程式 發表在 痞客邦 留言(0) 人氣()