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優先級
對於這兩個,我們可以把它們理解成一個微任務。也就是說,它其實不屬於事件循環的一部分。