macro-task(宏任務):包括整體代碼script,setTimeout,setInterval
micro-task(微任務):Promise,process.nextTick、
https://juejin.im/post/59e85eebf265da430d571f89#heading-4 原文
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})複製代碼
第一輪事件循環流程分析如下:
- 整體script作爲第一個宏任務進入主線程,遇到
console.log
,輸出1。 - 遇到
setTimeout
,其回調函數被分發到宏任務Event Queue中。我們暫且記爲setTimeout1
。 - 遇到
process.nextTick()
,其回調函數被分發到微任務Event Queue中。我們記爲process1
。 - 遇到
Promise
,new Promise
直接執行,輸出7。then
被分發到微任務Event Queue中。我們記爲then1
。 - 又遇到了
setTimeout
,其回調函數被分發到宏任務Event Queue中,我們記爲setTimeout2
。
宏任務Event Queue | 微任務Event Queue |
---|---|
setTimeout1 | process1 |
setTimeout2 | then1 |
-
上表是第一輪事件循環宏任務結束時各Event Queue的情況,此時已經輸出了1和7。
-
我們發現了
process1
和then1
兩個微任務。 - 執行
process1
,輸出6。 - 執行
then1
,輸出8。
好了,第一輪事件循環正式結束,這一輪的結果是輸出1,7,6,8。那麼第二輪時間循環從setTimeout1
宏任務開始:
- 首先輸出2。接下來遇到了
process.nextTick()
,同樣將其分發到微任務Event Queue中,記爲process2
。new Promise
立即執行輸出4,then
也分發到微任務Event Queue中,記爲then2
。
宏任務Event Queue | 微任務Event Queue |
---|---|
setTimeout2 | process2 |
then2 |
- 第二輪事件循環宏任務結束,我們發現有
process2
和then2
兩個微任務可以執行。 - 輸出3。
- 輸出5。
- 第二輪事件循環結束,第二輪輸出2,4,3,5。
- 第三輪事件循環開始,此時只剩setTimeout2了,執行。
- 直接輸出9。
- 將
process.nextTick()
分發到微任務Event Queue中。記爲process3
。 - 直接執行
new Promise
,輸出11。 - 將
then
分發到微任務Event Queue中,記爲then3
。
宏任務Event Queue | 微任務Event Queue |
---|---|
process3 | |
then3 |
- 第三輪事件循環宏任務執行結束,執行兩個微任務
process3
和then3
。 - 輸出10。
- 輸出12。
- 第三輪事件循環結束,第三輪輸出9,11,10,12。
整段代碼,共進行了三次事件循環,完整的輸出爲1,7,6,8,2,4,3,5,9,11,10,12。
(請注意,node環境下的事件監聽依賴libuv與前端環境不完全相同,輸出順序可能會有誤差)