1. 程式人生 > >JS JavaScript事件迴圈機制

JS JavaScript事件迴圈機制

區分程序和執行緒

程序是cpu資源分配的最小單位(系統會給它分配記憶體)

不同的程序之間是可以同學的,如管道、FIFO(命名管道)、訊息佇列

一個程序裡有單個或多個執行緒

瀏覽器是多程序的,因為系統給它的程序分配了資源(cpu、記憶體)(開啟Chrome會有一個主程序,每開啟一個Tab頁就有一個獨立的程序)

 

瀏覽器的渲染程序是多執行緒的

1.GUI渲染執行緒

2.JS引擎執行緒

3.事件觸發執行緒

4.定時觸發器執行緒

5.非同步HTTP請求執行緒

 

事件迴圈機制

 

上圖解釋:

同步和非同步任務分別進入不同的執行"場所",同步的進入主執行緒,非同步的進入Event Table並註冊函式

當指定的事情完成時,Event Table會將這個函式移入Event Queue

當棧中的程式碼執行完畢,執行棧(call stack)中的任務為空時,就會讀取任務佇列(Event quene)中的事件,去執行對應的回撥

如此迴圈,形成js的事件迴圈機制(Event Loop)

 

巨集任務(macrotask)和微任務(microtask)

先看一段程式碼的執行結果:

console.log('script start');

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

Promise.resolve().then(
function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end');

執行結果: script start , script end , promise1 , promise2 , setTimeout

 JS中分為兩種任務型別:macrotaskmicrotask,在ECMAScript中,microtask稱為jobs,macrotask可稱為task

  • macrotask(又稱之為巨集任務),可以理解是每次執行棧執行的程式碼就是一個巨集任務(包括每次從事件佇列中獲取一個事件回撥並放到執行棧中執行)

    • 每一個task會從頭到尾將這個任務執行完畢,不會執行其它

    • 瀏覽器為了能夠使得JS內部task與DOM任務能夠有序的執行,會在一個task執行結束後,在下一個 task 執行開始前,對頁面進行重新渲染 (task->渲染->task->...

  • microtask(又稱為微任務),可以理解是在當前 task 執行結束後立即執行的任務

    • 也就是說,在當前task任務後,下一個task之前,在渲染之前

    • 所以它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染

    • 也就是說,在某一個macrotask執行完後,就會將在它執行期間產生的所有microtask都執行完畢(在渲染前)

分別什麼樣的場景會形成macrotask和microtask呢?

  • macrotask:主程式碼塊,setTimeout,setInterval等(可以看到,事件佇列中的每一個事件都是一個macrotask)

  • microtask:Promise,process.nextTick等

補充:在node環境下,process.nextTick的優先順序高於Promise,也就是可以簡單理解為:在巨集任務結束後會先執行微任務佇列中的nextTickQueue部分,然後才會執行微任務中的Promise部分。

總結下執行機制:

  • 執行一個巨集任務(棧中沒有就從事件佇列中獲取)

  • 執行過程中如果遇到微任務,就將它新增到微任務的任務佇列中

  • 巨集任務執行完畢後,立即執行當前微任務佇列中的所有微任務(依次執行)

  • 當前巨集任務執行完畢,開始檢查渲染,然後GUI執行緒接管渲染

  • 渲染完畢後,JS執行緒繼續接管,開始下一個巨集任務(從事件佇列中獲取)

如圖: