什麼是 event loop ? ( JavaScript )

本文章參考至: 


了解Event Loop之前必須要先了解的專有名詞

Stack(堆疊)

資料型態的一種,特性是"先進後出"。

Queue(佇列)

資料型態的一種,特性是"先進先出"。


JavaScript 是如何運作的?

我們知道JavaScript是單線程型(single threaded)的程式語言,程式碼片段會以Stack的方式執行,所以一次只會執行一個程式碼片段,執行完之後才會換下一個。

程式碼的執行順序,是由最上方的程式碼開始,往下逐行執行。

JavaScript是以「後進先出」( LIFO, Last In First Out)執行堆疊(call stack)。而執行堆疊(call stack)也可以理解為是「執行當下的紀錄」

當開始執行程式,會從全域(Global Scope)的主程式(main program)開始執行,當進入某一個函式,便會把這個函式推(push)至執行堆疊(stack)的最上方,以此類推往上疊加並由最上層(也就是最後進入的)開始執行,而當該函式執行結束(return),便會將此函式從原本的最上層抽離(pop off),以此類推。

無限迴圈

無限迴圈就是因為不斷的疊加新的疊層直到出現問題或當掉。

怎麼樣的情況會導致網頁速度變慢?

在了解JavaScript的運作方式之後,我們知道當主程式運行到函式時會疊加新的疊層並開始處理。

但是當函式在處理時,你是不能進行其他動作的
而當處理時間太長時,整個網站就會像是"卡住"一樣,這種現象稱為"堵塞blocking"

(處理速度的快慢其實並沒有很明確的定義,但我們能還是大概感覺得出來,像是 console.log()很快 、執行while()迴圈一億次很慢、網站請求很慢、圖片請求很慢... 之類的。)

那如果要避免這種狀況,就要用到 非同步回調 ,那麼要如何做到非同步回調呢?

其實你在進行DOM操作設定的事件監聽器時,就已經在運用非同步的概念了,你先把函式準備好但不執行,等到事件發生時再進行處理。

這邊用一個簡單的例子:


我們可以來預想一下這個程式碼會如何運作
  • 一開始會先執行console.log('A'),然後移除
  • 設置事件監聽器,但還不會執行裡面的動作
  • 然後執行console.log('C'),並移除
  • 整個主程式運行完畢
  • 此時使用者點擊了按鈕,觸發了事件監聽器
  • 事件監聽器就神奇的出現,並執行了裡面的動作
  • 執行console.log('B'),並移除
  • 之後事件監聽器又默默的消失並等待下次的呼叫
大概像是這樣

你可能會想問:這是怎麼做到的,事件監聽器躲到哪裡去了??

這裡就要解釋一下 Wed APIs 了

Wed APIs

Wed Apis 為瀏覽器提供的方法,運作於瀏覽器端,由於並不是JavaScript引擎的一部份,所以可以與JavaScript同時運行。

常見的Wed Apis有 DOM、AJAX、setTimeout 詳細的可以看這裡MDN Web APIs

而本篇的主角 event loop 就是用於管理在背景運行的各種事件。

Event Loop 運作流程

Event Loop本質上就是一個監控器,用於協調各個事件的執行順序,以圖示來理解Event Loop的運行過程。


區域介紹

Call Stack

使用Stack資料型態
首先程式碼片段會先進到這邊執行,並在執行完成後移出,而非同步的動作進入 Web Apis 區域去做處理。

Wed APIs

這裡的非同步動作會在瀏覽器背景執行,並且執行沒有先後順序,誰先執行完成就會先進到 Callback Queue 去做等待。

Callback Queue

使用Queue資料型態,透過event loop監控並確認Call Stack清空後,依序將程式碼片段放回Call Stack中執行。

補充說明:

雖然可以透過將程式碼委託給Wed Apis來達成更流暢的運行,但還是要注意不要同時委託過多的動作導致執行完成時 Callback Queue 被塞住。

結語

event loop的運作機制真的很有趣,想了解非同步就一定得要了解他,至於要如何運用這些去優化你得程式碼,就得讓你自己去摸索了。

留言