JS事件循環中的宏任務和微任務執行順序

1. 宏任務和微任務事件

其中微任務的優先級高於宏任務,括號內爲事件運行環境

宏任務 微任務
I/O事件/onClick點擊事件 process.netTick (Node)
setTimeout NutationObserver(瀏覽器)
setImmediate(Node) Promise
setInterval
requestAnimationFrame(瀏覽器)

2. 優先級更清晰的版本

idle觀察者 > I/O觀察者 > check觀察者

觀察者 觀察事件
idle觀察者 process.netTick
I/O觀察者 一般性的I/O回調,如:網絡,文件數據庫I/O等
check觀察者 setTimeout,setImmediate

3. 詳解setTimeout和setImmediate優先級

事件在瀏覽器中的常見概念的eventLoop和Node環境中的循環事件大致相同,最大的不同Node中事件循環分不同的階段詳情戳鏈接

這兩個事件同時存在僅有可能運行在node環境中,下圖爲node事件循環不同階段示意圖:
在這裏插入圖片描述

setTimeout(() => {
    console.log('setTimeout');
}, 0);
setImmediate(() => {
    console.log('setImmediate');
})
// 輸出有兩種情況
// setImmediate
// setTimeout
// 或者
// setImmediate
// setTimeout

爲什麼會這樣子呢?

這裏我們要根據前面的那個事件循環不同階段的圖解來說明一下:

首先進入的是timers階段,如果我們的機器性能一般,那麼進入timers階段,一毫秒已經過去了(setTimeout(fn, 0)等價於setTimeout(fn, 1)),那麼setTimeout的回調會首先執行。

如果沒有到一毫秒,那麼在timers階段的時候,下限時間沒到,setTimeout回調不執行,事件循環來到了poll階段,這個時候隊列爲空,此時有代碼被setImmediate(),於是先執行了setImmediate()的回調函數,之後在下一個事件循環再執行setTimemout的回調函數。

而我們在執行代碼的時候,進入timers的時間延遲其實是隨機的,並不是確定的,所以會出現兩個函數執行順序隨機的情況。

以下兩種情況setImmediate永遠先於setTimeout執行:

var fs = require('fs')

fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log('timeout');
    }, 0);
    setImmediate(() => {
        console.log('immediate');
    });
});
setTimeout(() => {
    setImmediate(() => {
        console.log('setImmediate');
    });
    setTimeout(() => {
        console.log('setTimeout');
    }, 0);
}, 0);

4. 詳解process.nextTick() 和 Promise優先級

對於這兩個,我們可以把它們理解成一個微任務。也就是說,它其實不屬於事件循環的一部分。

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