主要的原因有兩個 :
圖片來源:Event loop and the rise of Async
Event Loop協助了非同步請求的實現,並產生連貫的畫面(influent UI)
Event Loop將"費時較久"或"需等待事件才能啟動"的任務往後排,因此能讓使用者有流暢的使用者體驗(Outstanding UX)
圖片來源:搞懂非同步請求 (Asynchronous request)概念
在javascript誕生之前的瀏覽器,當使用者打開網頁,填寫完內容並提交表單進入等待畫面,過了30s才傳來某個地方資料填寫錯誤的提醒訊息。
js出現後,在前端就能協助用戶檢查表單填寫的內容格式是否正確,不必透過server端處理才回傳。
在Google Chrome尚未誕生的1990年代,網路巨擘Netscape為了自家的瀏覽器,請當時任職的Brendan Eich設計一個「可提供複雜網頁互動」的語言原型---就是Javascript。
為了讓開發者可以專注在程式開發上,Javascript被設計為「單線程(single threaded runtime)」,一次只執行一小段程式碼,而不必煩惱「併發性問題(concurrency issue)」。
因為Javascript一次只做一件事,當所render的資料來源為第三方API,在瀏覽器等待response時,畫面就會停在奇怪的讀取畫面。
因此Event Loop就在這樣的情況下因應而生,可以說是附著在瀏覽器的監聽器,用以管控各項任務順暢執行。
一個後進先出的執行推疊(call stack),會依序執行函式 : 從全域(Global Scope)的主程式開始,逐一把各個函式推(push)至執行推疊上方,並從最後進入的函式開始執行,當函式結束後,會將此函式抽離堆疊(pop off)。
瀏覽器提供了很多不同的API(ex.DOM, AJAX, Timeout),讓我們可以同時處裡多項任務。當完成Web APIs的內部函式後(settimeout秒數到),便將任務傳遞至工作佇列。
一個先進先出的工作佇列(call queue)。會接收從Web API來的任務,並透過Event Loop的監控,當Call stack中沒有執行項目時,便把佇列中的內容拉近堆疊中。
Philip Roberts 自己寫了一個方便視覺化瞭解 JavaScript Runtime, call stack, event loop, task queue 的工具 Loupe ,你可以把下面摘錄自各說明文章的例子,貼到他所提供的網站中執行。
const bar = function() {
console.log("bar");
};
const baz= function() {
console.log("baz");
};
function foo() {
console.log("foo");
bar();
baz();
}
foo();
圖片來源:A simple example
console.log("Hi")
setTimeout(function cb() {
console.log("cb1")
},5000)
console.log("Bye")
圖片來源:A simple example
參考來源:
並行模型和事件循環
Javascript 的事件循環 (Event Loop)
理解JS中事件循環