js執行機制淺析

程式碼在路上ing發表於2019-04-16

js執行機制

眾所周知,js是一門單執行緒的語言。主要同他的用途有關,同一個時間只能做一件事兒,作為瀏覽器指令碼語言,JavaScript的主要用途是與使用者互動,以及操作DOM,這決定了它只能是單執行緒,否則會帶來很複雜的同步問題。

js事件迴圈

由於javaScript的資源載入是按序進行的,javaScript的單執行緒決定只有一個任務結束才可以執行下一個任務,否則只能是下一個任務處於等待狀態。而任務分為同步任務與非同步任務:
同步任務:在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
非同步任務:不進入主執行緒、而進入"任務佇列"的任務,只有"任務佇列"通知主執行緒,某個非同步任務可以執行了,該任務才會進入主執行緒執行;
通常我們會將網頁的Dom渲染作為同步任務,將獲取遠端資料,圖片載入等操作作為非同步任務進行。

js任務執行順序

  1. 全部的同步任務會進入主執行緒,非同步任務進入Event Table並註冊函式,Event Table會將這個函式移入Event Queue。
  2. 主執行緒任務執行完畢後,js引擎存在monitoring process程式,會持續不斷的檢查主執行緒執行棧是否為空,一旦為空,就會去Event Queue那裡檢查是否有等待被呼叫的函式,進入主執行緒執行。
  3. 以上兩步會迴圈進行

setTimeout,promise以及async

佇列任務優先順序:

promise.Trick() > promise的回撥 > async > setTimeout > setInterval

巨集任務與微任務的區分:

巨集任務:包括整體程式碼script,setTimeout,setInterval
微任務:Promise,process.nextTick

事件迴圈的順序

事件迴圈的順序決定js程式碼的執行順序,進入整體程式碼(巨集任務)後,開始第一次迴圈。所有的同步任務先執行,根據任務型別部分非同步任務進入入Event Queue,部分非同步任務進入不同的Event Queue,巨集任務的第一次迴圈結束後接著執行所有的微任務。然後再次從巨集任務開始,找到其中一個任務佇列執行完畢,再執行所有的微任務。

面試題

console.log('start')
async function async1() {
   console.log("async1");
   await  async2();
   console.log("async1");
}
async  function async2() {
    console.log( 'async2');
}
console.log("script");
setTimeout(function () {
    console.log("setTimeout");
},0);
async1();
new Promise(function () {
    console.log("promise1");
}).then(function () {
    console.log("promise2");
});
複製程式碼

輸出:

start
script
async1
async2
promise1
promise2
async1
setTimeout
複製程式碼

解析: 首先執行所有的同步任務,async與await搭配使用時是非同步任務,async單獨定義函式時則當做同步任務執行,所以輸出start,script,遇到setTimeout將其放在入Event Queue任務佇列中,執行async1函式後 輸出async1,async2,此時要等待async2執行完畢,將其放在微任務的Event Queue中,所以此時主執行緒執行下面的程式碼,new Promise例項會立即執行,輸出promise1,碰到then非同步函式進入Event Queue任務佇列中,此時巨集任務第一輪執行完畢,去執行所有的微任務,微任務執行結束後將巨集任務的任務佇列的非同步任務放在主執行緒進行執行。

相關文章