Javascript運行機制

Javascript是一種單線程開發語言。理解Javascript的運行機制是平常編碼必需要掌握的技能。

爲何是單線程?

JavaScript的主要用途是與用戶交互,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題。git

  • 假設:若是JavaScript支持多線程,一個線程在某個DOM節點上添加內容,另一個線程刪除了這個節點,那麼瀏覽器該以哪一個線程爲準呢?

單線程的缺點

單線程就意味着容易發生線程等待資源,cpu空閒,而其餘任務一直等待的問題。github

什麼是Event Loop(事件循環)

爲了協調事件、用戶交互、腳本、UI 渲染和網絡處理等行爲,防止主線程阻塞。因而Javascript設計者將全部任務分爲兩種,一種是同步任務,一種是異步任務promise

  • 同步任務指的是,在主線程上排隊執行的任務瀏覽器

    • 同步任務只有前一個任務執行完畢,才能執行下一個任務。
    • 同步任務都在主線程上執行,造成一個執行棧網絡

      • 每次執行棧執行的代碼就是一個宏任務
  • 異步任務指的是,不進入主線程,而進入任務隊列的任務。數據結構

    • 只要指定過回調函數,這些事件發生時就會進入"任務隊列"(好比鼠標點擊...等)
    • 一旦執行棧中的全部同步任務執行完畢,系統就會讀取「任務隊列」。
    • 任務隊列是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。

"主線程"從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop(事件循環)。多線程

宏任務和微任務

根據規範:每一個任務都有一個任務源(task source),源自同一個任務源的 task 必須放到同一個任務隊列,從不一樣源來的則被添加到不一樣隊列,因此有了宏任務(macro)task和微任務(micro)task。異步

瀏覽器爲了可以使得JS內部(macro)task與DOM任務可以有序的執行,會在一個task執行結束後,在下一個(macro)task 執行開始前,對頁面進行從新渲染,函數

每次執行完一個宏任務以後,會去檢查是否存在微任務;若是有,則執行微任務直至清空微任務隊列,若是在微任務執行期間微任務隊列加入了新的微任務,會將新的微任務加入隊列尾部,以後也會被執行。oop

根據上述總結流程爲:

流程圖

附(宏/微任務清單):

  • 宏任務(macro)task主要有: script(總體代碼)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 環境)
  • 微任務(micro)task主要有: Promise.then、MutaionObserver、process.nextTick(Node.js 環境)
  • requestAnimationFrame 既不屬於宏任務, 也不屬於微任務

目前宏任務和微任務在各瀏覽器執行都有差別,最後提議promise爲微任務

實例分析

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

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

    console.log('4');

以上案例會輸出 2 4 3 1

結果解析:

  1. JavaScript執行主線程任務:輸出 2 4

    • 附:Promise構造器內部是同步任務
  2. 執行微任務隊列:輸入 3
  3. 第一個宏任務結束,進入setTimeout回調:輸出 1

End

持續更新中 來Github 點顆⭐吧

返回主頁

相關文章
相關標籤/搜索