(上一篇只有複習,沒有帶到題目,所以這篇會解釋兩個問題,答案可以直接看結論~)
在上一篇文章 7. 解釋 Event Loop ( 上 ) --- Call Stack有提到,非同步的程式設計是為了解決單執行緒在事件的處理上,沒有效率的問題。
而這篇文章的主題 —— Event Loop,就是用來控制在JS裡同步與非同步事件的運行:
(以 Google Chrome的V8引擎為例。 )
解釋一下這張圖:
JavaScript Engine本身涵蓋兩個Components:
許多我們在瀏覽器使用的API(e.g. DOM, AJAX, Timeout...),並非來自JS引擎,而是由瀏覽器的 Web APIs 提供。
所有被放進Async Function裡,作為參數的function,被稱作"callback",這些callback被依序放在 callback queue 等待執行。(負責排序非同步執行函式)
→ 所有執行環境的共通點,就是都有一個叫"event loop"的內建機制。
它會隨著時間執行上述被分類的任務,並在每次執行時調用JS引擎。
( ↑ 全文重點
+++++++++++++++++++++++++
整理一下邏輯關係:
+++++++++++++++++++++++++
我們已經知道DOM, AJAX, Timeout...都是由Web APIs提供的API,而當我們使用這些API進行非同步的呼叫(callback function),
Event Loop 會將 callback function 放進 Callback Queue (佇列)。
( 我自己在解釋的時候偏好講Callback Queue,但因為題目寫Task Queue,所以下面結論是講Task Queue。)
佇列也是資料結構的一種,特色是先進先出(First-In-First-Out, FIFO)。
假設物件依照a, b, c的順序被放入,越早放入的會越早取出,所以取出的順序也是a, b, c。
A JavaScript runtime uses a message queue, which is a list of messages to be processed. Each message has an associated function which gets called in order to handle the message.
→ 直到Call Stack被清空,Event Loop會將Callback Queue裡最早紀錄的訊息(message)放入Call Stack,直到Callback Queue裡的message也被清除完成。
這裡可以執行一個例子:
console.log('start');
setTimeout(function callback() {
console.log('callback is here');
}, 3000);
console.log('end');
setTimeout()的執行方式
setTimeout()並不會直接將callback交給event Loop,他會先建造自己的計時器(timer),直到計時結束,才將將callback放進callback queue。
→ 因此,上面例子的3000
不是指3秒後就會執行程式,而是3秒後才會被放進佇列。
start
end
callback is here // 3秒後出現
然後上面的執行順序是這樣的: gif和圖檔(這次圖片放進來反而有點亂,所以和gif的連結放在一起。)
console.log('start')
放進call stack;執行console.log('start')
。console.log('end')
放進call stack;執行console.log('end')
。callback()
進入【Callback Queue】callback()
放進call stack;執行callback()
。\ | 【In Call stack】| 【In web api】| 【In Callback Queue】|
-----|-----|-----
1 | console.log('start')
放進call stack;執行console.log('start')
。| --- | --- |
2 | --- | setTimeout(callback()
)建立timer,等3秒... | ↘ |
3 | console.log('end')
放進call stack;執行console.log('end')
。 | --- | ↓
4 | --- | --- | 3秒結束,callback()
進入【Callback Queue】|
5 | callback()
放進call stack;執行callback()
。 | ← | ← |
解釋Event Loop的運作?
因為JS的執行是單執行緒的,在處理同步事件時,會將函式放在Call Stack執行。
如果是請求資料或滑鼠點擊之類的非同步事件,則會將事件交給瀏覽器提供的Web APIs,在解析完成後,放到Task Queue,等待Call Stack裡的函式執行完畢後,再繼續將Task Queue裡的函式依序放入Call Stack,並完成剩餘函式。
Call Stack和Task Queue的差異?
Call Stack用於同步事件的函式執行,Task Queue用於非同步事件的函式執行,而Call Stack裡的工作會先被執行完畢。
Call Stack的結構是後進先出(LIFO),越早放進Call Stack的函式會越晚被執行;而Task Queue則是先進先出(FIFO),被放進Task Queue的函式,會依照放入順序執行。
【如內文有誤還請不吝指教>< 謝謝閱覽至此的各位:D】
參考資料:
-----正文結束-----
我自己是會聽歌聽到捨不得去睡覺的人,所以事情做不完的時候,音樂放出來我就會乖乖做下去了。
前陣子才把《La La Land》補完,但在看電影之前就很喜歡《City Of Stars》這首歌。