JS 筆記 | Event Loop

閱讀時間約 3 分鐘

在講什麼是 Event loop 之前必須先記得 JavaScript 的運作方式是單執行緒 (single-threaded),也就是它一次只能做一件事情,所有的函式都得乖乖排隊等著被執行,這種事件又叫做同步 (synchronous)

在同步下,程式碼中的函式一多,或者複雜度提高,就增加了排隊等著被執行的時間,大概就有點像是大家在高速公路上排隊等著下交流道,然後就會很驚喜地發現:哇喔,網頁卡住了!這種塞住的現象被稱作阻塞 (blocking)。但是很明顯,做為開發網頁的第一大語言,JavaScript 一定會克服這種阻塞的現象來造就現在大家使用的這麼順暢的網頁 UI,於是非同步 (asynchronous) 就出現了!

非同步的出現可以讓 JavaScript 並發 (concurrency) 運作程式碼中的函式,讓單線程的執行變成多線程,因此避免了阻塞的發生。這樣的結果就是需要依賴今天的主角 Event loop 啦!

再來談談 Call stack, Web API, Callback queue。Call stack 會追蹤我們呼叫的函式,通常來說,在同步下就只會有Call stack 的存在,所以阻塞就是阻塞在 Call stack 這裡,可以把它想像成高速公路的交流道,一堆車子都擠在這裡等著下去。

JavaScript 的非同步,在 Call stack 中出現瀏覽器負責處理的函式 (如 setTimeout) 時,會從 Call stack 中將該函式取出丟到 Web API 的地方去執行,執行完畢再丟到 Callback queue 去,等著再被塞回 Call stack 中去輸出結果。

那 Event loop 呢?Event loop 哪裡去了?Event loop 所扮演的角色就是當 Call stack 中為空閒時,把 Callback queue 的回調函式 (callback) 丟回 Call stack 中。

這樣做的好處就是如setTimeout在 Web API 中執行時,其他不需要進入到 Web API 的程式碼,比如console.log直接可以在 Call stack 中執行而不用去乖乖等待setTimeout執行完畢,達到分流的效果。



舉個 Philip Roberts 在 JSConf EU 介紹 event loop 中的例子:

console.log(‘hi’);

setTimeout(function cb(){
console.log(‘there’);
}, 5000);

console.log(‘JSConfEU’)

產出的結果順序會是:

  1. hi
  2. JSConfEU
  3. there

按照前面講的非同步來解釋事情是怎麼發生的:

  1. console.log(‘hi’)塞入 Call stack,執行,移出 Call stack。
  2. setTimeout塞入 Call stack,在 Web API 啟動倒數計時,移出 Call stack 。
  3. console.log(‘JSConfEU’)塞入 Call stack,執行,移出 Call stack。
  4. Web API 繼續執行倒數計時。
  5. 倒數計時結束,cb塞入 Callback queue。
  6. console.log(‘there’)塞入 Call stack,執行,移出 Call stack。
來個圖解會更清楚~

來個圖解會更清楚~

那如果今天把setTimeout設定為0呢?會得到不一樣的順序嗎?答案是不會,輸出結果順序依然跟倒數5秒一樣,那是因為setTimeout這個函式必然是要進入 Web API, Callback queue 然後再回到 Call stack 跑上這麼一圈的。



推薦大家去看看 Philip Roberts 在 JSConf EU 的影片:


18會員
37內容數
這個專題用來存放我在學習網頁開發時的心得及知識。
留言0
查看全部
發表第一個留言支持創作者!
從 Google News 追蹤更多 vocus 的最新精選內容