JS事件輪詢機制(Event Loop)

概念

    事件輪詢 (eventloop) 是"一個解決和處理外部事件時將它們轉換爲回調函數的調用的實體(entity)"

    JavaScript 語言的一大特點就是單線程,也就是說,同一個時間只能做一件事。所有任務都需要排隊,前一個任務結束,纔會執行後一個任務。如果前一個任務耗時很長,後一個任務就不得不一直等着。
在這裏插入圖片描述

任務隊列

    “ 任務隊列 " 是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空," 任務隊列 " 上第一位的事件就會自動進入主線程。

    所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。

    同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務

    異步任務指的是,不進入主線程、而進入 " 任務隊列 "(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務纔會進入主線程執行。

JS如何實現異步操作

    JS 的異步是通過回調函數實現的,即通過任務隊列,在主線程執行完當前的任務棧(所有的同步操作),主線程空閒後輪詢任務隊列,並將任務隊列中的任務(回調函數)取出來執行。

    " 回調函數 "(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。

    雖然 JS 是單線程的,但是瀏覽器的內核是多線程的,在瀏覽器的內核中不同的異步操作由不同的瀏覽器內核模塊調度執行,異步操作會將相關回調添加到任務隊列中。而不同的異步操作添加到任務隊列的時機也不同,如 onclick, setTimeout,ajax 處理的方式都不同,這些異步操作是由瀏覽器內核的 webcore 來執行的,webcore 包含上圖中的3種 webAPI,分別是 DOM Binding、network、timer模塊。

  • onclick 由瀏覽器內核的 DOM Binding 模塊來處理,當事件觸發的時候,回調函數會立即添加到任務隊列中。
  • setTimeout 會由瀏覽器內核的 timer 模塊來進行延時處理,當時間到達的時候,纔會將回調函數添加到任務隊列中。
  • ajax 則會由瀏覽器內核的 network 模塊來處理,在網絡請求完成返回之後,纔將回調函數添加到任務隊列中。

異步執行機制

  • 所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。
  • 主線程之外,還存在一個 " 任務隊列 "(task queue)。只要異步任務有了運行結果,就在 " 任務隊列 " 之中放置一個事件。
  • 一旦 " 執行棧 " 中的所有同步任務執行完畢,系統就會讀取 " 任務隊列 ",看看裏面有哪些事件。於是那些對應的異步任務結束等待狀態,進入執行棧,開始執行。
  • 主線程不斷重複上面的第三步(事件輪詢)

JS中事件隊列的優先級

    在 JS 的ES6 中新增的任務隊列(promise)優先級是在事件循環之上的,事件循環每次 tick 後會查看 ES6 的任務隊列中是否有任務要執行,也就是 ES6 的任務隊列比事件循環中的任務(事件)隊列優先級更高。

  • setTimeout( fn, 0 ),它在 " 任務隊列 " 的尾部添加一個事件,因此要等到同步任務和 " 任務隊列 " 現有的事件都處理完,纔會得到執行。
console.log(1)
setTimeout(function () {
	console.log(6)
}, 1000)
new Promise(function (resolve, reject) {
    console.log(2)
    setTimeout(function () {
        console.log(3)
    }, 500)
    resolve()
}).then(function (res) {
    console.log(4)
})
console.log(5)

// 1 2 5 4 3 6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章