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中分為兩種任務型別:macrotask
和microtask
,在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等
總結下執行機制:
-
執行一個巨集任務(棧中沒有就從事件佇列中獲取)
-
執行過程中如果遇到微任務,就將它新增到微任務的任務佇列中
-
巨集任務執行完畢後,立即執行當前微任務佇列中的所有微任務(依次執行)
-
當前巨集任務執行完畢,開始檢查渲染,然後GUI執行緒接管渲染
-
渲染完畢後,JS執行緒繼續接管,開始下一個巨集任務(從事件佇列中獲取)