# [JS 筆記] event loop ### 單執行緒(single Thread) Javascript(以下簡稱JS) 是一種單執行緒(single Thread),指的是JS一次只能執行做一件事,或是同一時間只能執行一段程式碼(一行一行執行)。 ### 呼叫推疊(Call Stack) 而當程式執行時,怎麼確定執行順序? Call Stack會記錄目前程式執行的位置,如果執行到一個函式(function),會將函式pop in Stack 中,等函式執行結束,才會將其pop out Stack。參考 [Call Stack動畫介紹](https://www.youtube.com/watch?v=Q2sFmqvpBe0),可以特別注意到Stack採用FILO(First In Last Out);而待會也會介紹到的Queue是FIFO。 --- ### 阻塞(Blocking) 因此,當程式碼一多,且Call Stack 必須一層層執行,當上層任務沒結束前,下層任務則無法開始,可想而知,若沒有安排好或是解決方式,勢必會塞車,這種狀況,稱阻塞(Blocking)。若是在前端,配合UI/UX時,網頁畫面則會產生更明顯的資料不同步,和延遲的狀況,而造成使用者體驗差。 ### 非同步回呼(Asynchronous Callback) 為了避免程式碼發生阻塞,最常見的處理方式,就是非同步回呼(Asynchronous Callback)。 ``` console.log('Hi') setTimeout(function cb() { console.log('There') }, 5000) console.log('JSConfEU') ``` 可以將他SOP,整理成 1. 若同步的動作則直接執行 1. 非同步的動作則丟到 Web Apis 做處理 1. 若 function 內有另一個 function 則向上堆疊( Stack ) 1. 執行完成後則移出 Call Stack 當我們在瀏覽器中輸入會發現,Hi JSConfEU很快就印出來了,過了5秒後There才印出,將程式碼切細,分成: 1. 印出Hi 2. 執行setTimeout,傳到 WebAPIs準備5秒等待時間到 3. 印出JSConfEU 4. 5秒時間到,傳至Callback Queue 5. 傳回至Stack 6. 印出There ### 瀏覽器內的執行 > 為甚麼JS是單執行緒,卻沒有依序印出? > 甚麼是WebAPIs、Callback Queue? JS的確只能執行單執行緒,但可以一起做很多事,而不是僅提供一個運行環境,瀏覽器還提供很多WebAPI,常見的如:document、XMLHttpRequest、setTimeout...給我們使用,但由於他們不在V8引擎中,只能以呼叫方式去執行這些功能。因此,當瀏覽器知道你要呼叫他們來用的時候,就可以和你的程式碼同時一起執行 (Concurrency) ,也不會影響到你的 JS 主程式。  整個流程如上, * Heap:程式中宣告、定義變數、函式…等的記憶體位置 * Stack:程式中要執行的函式 pop in 的地方,一次執行一個,完成後 pop out。 * WebAPIs:當要執行的程式為非同步 WebAPIs,瀏覽器即會和程式一起開始執行,當他執行完,也不會把結果隨便丟回你的程式中,他會去排進 Callback Queue 中。 * Callback Queue / Task Queue:這裡就是儲放 callback function 的地方,等著被丟進 Stack 被執行。 * Event Loop:Event Loop 會持續查看 Stack 空下來了沒有,如果已經空了,就把 Callback Queue 裡面的任務丟進 Stack 讓他去執行。 了解以上流程後,再看一個例子 ``` function A() { console.log("functionA"); setTimeout(() => console.log("setTimeout1"), 2000); B(); } function B() { console.log("functionB"); setTimeout(() => console.log("setTimeout2"), 1000); } console.log("start"); A(); console.log("end"); ``` 實際看一下 Demo 來了解運作,以上分別有 A、B 兩個函式,內部分別還有一個 setTimeout,而 A 函式會呼叫 B 函式,讓我們來看看 console.log 出來的順序 ``` start functionA functionB end setTimeout2 setTimeout1 ``` 大概流程如下: * 將 console.log("start") 丟入 Call Stack 執行,完成後移出 * 將 A 函式丟入 Call Stack 執行 * 將 console.log("functionA") 丟入 Call Stack 執行,完成後移出 * 將 setTimeout1 丟到 Web Apis 執行 * 將 B 函式丟入 Call Stack 執行 * 將 console.log("functionB") 丟入 Call Stack 執行,完成後移出 * 將 setTimeout2 丟到 Web Apis 執行 * B 函式執行完成,移出 Call Stack * A 函式執行完成,移出 Call Stack * 將 console.log("end") 丟入 Call Stack 執行,完成後移出 * 經過一秒後 setTimeout2 執行完成,並將 callback 放入 Callback Queue * Call Stack 為空,將 Callback Queue 內的 setTimeout2 callback 放入 Call Stack 執行 * console.log("setTimeout2") 執行完畢後移出 * 經過兩秒後 setTimeout1 執行完成,並將 callback 放入 Callback Queue * Call Stack 為空,將 Callback Queue 內的 setTimeout1 callback 放入 Call Stack 執行 * console.log("setTimeout1") 執行完畢後移出 --- ### 參考 * [所以說event loop到底是什麼玩意兒?| Philip Roberts | JSConf EU ](https://www.youtube.com/watch?v=8aGhZQkoFbQ) * [JavaScript - Event Loop](https://ithelp.ithome.com.tw/articles/10230871) ### 補充 * [[JavaScript] Javascript 的事件循環 (Event Loop)、事件佇列 (Event Queue)、事件堆疊 (Call Stack):排隊](https://medium.com/itsems-frontend/javascript-event-loop-event-queue-call-stack-74a02fed5625) * [Day 11 [EventLoop 01] 一次弄懂Event Loop(徹底解決此類面試問題)](https://ithelp.ithome.com.tw/articles/10241081) ###### tags: `JS筆記` `面試問題集`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up