1. 程式人生 > >徹底弄懂JavaScript 執行機制

徹底弄懂JavaScript 執行機制

很多人在面試的時候都會碰到這麼一道面試題:給一段程式碼,寫出執行結果和順序。其中側重的知識點可能也不盡相同。寫這篇文章,主要是把其中可能涉及到的知識點都簡單說一下,自己也好好梳理一下。如果文章有說的不對的地方,儘管diss

瀏覽器核心分為渲染引擎和JS引擎,不過由於JS引擎越來越獨立,核心就特指渲染引擎了。常見瀏覽器核心:IE-Trident引擎、Firefox-gecko引擎、Chrome/safari-webkit引擎、opera-Presto引擎後棄用使用webkit引擎、

  • 渲染引擎負責對網頁語法的解釋並渲染網頁。渲染引擎決定了瀏覽器如何顯示網頁的內容以及頁面的格式資訊。不同的瀏覽器核心對網頁編寫語法的解釋也有不同,因此同一網頁在不同的核心的瀏覽器裡的渲染(顯示)效果也可能不同 。
  • JS引擎:解釋並編譯程式碼,也就是執行JS程式碼的。單執行緒(如果是多執行緒,那對於同一個dom一個程序刪除一個程序編輯,瀏覽器會很尷尬,不知道怎麼辦),那麼問題來了,既然是單執行緒那如果遇到耗時很長的任務(載入超高清圖片)那後面的任務豈不是會很生氣,偉大的程式設計師當然有辦法解決這個問題了,那就是把任務分為同步任務和非同步任務,頁面元素渲染這種就放到同步任務裡面,資料請求,圖片載入這種耗時長的就放進非同步任務。盜圖一張

有點抽象,來段程式碼解釋一下

let data = [];
$.ajax({
    url:www.javascript.com,
    data:data,
    success:() => {
        console.log('傳送成功!');
    }
})
console.log('程式碼執行結束');
  1.  ajax進入Event Table,註冊回撥函式success
  2. 執行console.log('程式碼執行結束')
  3. ajax事件完成,回撥函式進入Event Queue
  4. 主執行緒從Event Queue讀取回調函式並執行

上述過程不斷重複,就是所謂的Event Loop(事件迴圈)

那如果用過promise的同學要問了,promise和setTimeout都是非同步任務,執行順序是怎樣的呢。任務當然還有更精細的劃分,不然提出這個問題解決不了,豈不是很尷尬。

  • macro-task(巨集任務):包括整體程式碼script,setTimeout,setInterval
  • micro-task(微任務)
    :Promise,process.nextTick

js程式碼執行的順序(也是時間迴圈的順序),相同型別任務會進入相同的Event Queue,進入整體程式碼(巨集任務)後,開始第一次迴圈。接著執行所有的微任務。然後再次從巨集任務開始,找到其中一個任務佇列執行完畢,再執行所有的微任務。好吧,有點抽象,舉個栗子

setTimeout(function() {
  console.log('setTimeout');
})

new Promise(function(resolve) {
  console.log('promise');
}).then(function() {
  console.log('then');
})

console.log('console');
  • 這段程式碼作為巨集任務,進入主執行緒。
  • 先遇到setTimeout,那麼將其回撥函式註冊後分發到巨集任務Event Queue。
  • 接下來遇到了Promisenew Promise立即執行,then函式分發到微任務Event Queue。
  • 遇到console.log(),立即執行。
  • 這時整體程式碼script作為第一個巨集任務執行結束,看看有哪些微任務?我們發現了then在微任務Event Queue裡面,執行。
  • ok,第一輪事件迴圈結束了,我們開始第二輪迴圈,當然要從巨集任務Event Queue開始。我們發現了巨集任務Event Queue中setTimeout對應的回撥函式,立即執行。
  • 結束。

這裡再說一下setTimeout,都知道這是用來進行非同步延遲任務的,但並不意味著程式碼是在設定的時間後執行,而是指經過設定的時間把要執行的任務加入到Event Queue中,又因為是單執行緒任務要一個一個執行,如果當前佇列前面的任務需要的時間太久,那麼只能等著,導致實際時間超過設定的時間。

setTimeout(fn,0)的含義是,指定某個任務在主執行緒最早可得的空閒時間執行,意思就是不用再等多少秒了,只要主執行緒執行棧內的同步任務全部執行完成,棧為空就馬上執行。要補充的是,即便主執行緒為空,0毫秒實際上也是達不到的。根據HTML的標準,最低是4毫秒。

對於setInterval(fn,ms)來說,我們已經知道不是每過ms秒會執行一次fn,而是每過ms秒,會有fn進入Event Queue。一旦setInterval的回撥函式fn執行時間超過了延遲時間ms,那麼就完全看不出來有時間間隔了

JavaScript執行機制-Event Loop