EA Play會員今日可以提前試玩《FIFA 22》
阿新 • • 發佈:2021-09-23
js執行機制
js是單執行緒的。通過執行機制模擬實現”多執行緒“。
如何實現多執行緒?
從廣義上,分為同步任務和非同步任務。
同步任務指的是,在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
非同步任務指的是,不進入主執行緒、而進入”任務佇列“(tack queue)的任務,只有”任務佇列“通知主執行緒,某個非同步任務可以執行了,該任務才會進入主執行緒執行。
- 同步和非同步任務分別進入不同的執行場所,同步的進入主執行緒,非同步的進入Event Table並註冊函式。
- 當Event Table中指定的事情完成時(比如delay,ajax),會將這個函式移入Event Queue。
- 主執行緒內的任務執行完畢為空,才回去Event Queue讀取對應的函式,進入主執行緒執行。
- 上述過程會不斷重複,也稱為事件迴圈(Event Loop)。
- js引擎存在monitoring process程序,不斷檢查主執行緒執行棧是否為空,一旦為空,就去Event Queue那裡檢查是否有等待被呼叫的函式。
對任務更精細的定義,分為巨集任務和微任務。
macro-task(巨集任務):包括整體程式碼script、setTimeout、setInterval
micro-task(微任務):Promise、process.nextTick.
不同型別的任務會進入對應的Event Queue。
Promise與事件迴圈
Promise在初始化時,傳入的函式時同步執行的,然後註冊then回撥。註冊完之後,繼續往下執行同步程式碼,在這之前,then的回撥不會執行。同步程式碼執行完畢後,才會在事件迴圈中檢測是否有可用的promise回撥,如果有,那麼執行,如果沒有,繼續下一個事件迴圈。
- 巨集任務、微任務都是佇列,一段程式碼執行時,會先執行巨集任務中的同步程式碼。
- 進入第一輪事件迴圈的時候會把全部的js腳本當成一個巨集任務來執行。
- 如果執行中遇到setTimeout之類的巨集任務,那麼就把這個setTimeout內部的函式推入【巨集任務的佇列】中,下一輪巨集任務執行時呼叫。
- 如果執行中遇到promise.then()之類的微任務,就會推入到【當前巨集任務的微任務佇列】中,在本輪巨集任務的同步程式碼都執行完成後,依次執行所有的微任務。
- 第一輪事件迴圈中當執行完全部的同步指令碼以及微任務佇列中的事件,這一輪事件迴圈就結束了,開始第二輪事件迴圈。
- 第二輪事件迴圈同理先執行同步指令碼,遇到其他巨集任務程式碼塊繼續追加到【巨集任務的佇列】,遇到微任務,就會推入到【當前巨集任務的微任務佇列】中,在本輪巨集任務的同步程式碼都執行完成後,依次執行當前所有的微任務。
- 開始第三輪迴圈...
總結:首次進入事件迴圈,會把整個js程式碼當作巨集任務執行,執行所有同步指令碼,遇到其他巨集任務程式碼塊繼續追加到【巨集任務的佇列】,下一輪巨集任務執行時呼叫,繼續本輪巨集任務程式碼執行,遇到微任務,推入到【當前巨集任務的微任務佇列】中,在本輪巨集任務的同步程式碼都執行完成後,依次執行所有的微任務。