如果面試官問你 JS中的event loop
是什么省咨?我相信大多數(shù)人都能答出來JS是單線程語言,只有一個主線程執(zhí)行玷室,執(zhí)行棧零蓉,同步、異步之類穷缤。但是敌蜂,這樣的理解只是淺層的,如果面試官要你再深入解釋津肛,我相信大多數(shù)人都卡住了章喉,不知道還能解釋什么,那么身坐,問題來了秸脱,這種情況怎么辦?
來看這篇文章部蛇,看完了你就知道怎么辦了撞反。
JS頁面的任務(wù)不僅可以按照同步異步來分,也可以分為macro-task
和micro-task
macro-task都有:包括整體代碼script搪花,setTimeout遏片,setInterval
micro-task都有:Promise嘹害,process.nextTick
頁面初始化時,不同的任務(wù)會進入到不同的 Event Queue(事件隊列)
初始化時吮便,會執(zhí)行所有代碼笔呀,將setTimeout等加入到macro-task
的事件列表,將Promise等加入到micro-task
事件列表髓需。
遇到立即執(zhí)行的代碼许师,則立即執(zhí)行,之后僚匆,會將事件列表中所有的micro-task
都執(zhí)行完畢微渠。
第一輪事件循環(huán)結(jié)束。
第二輪事件循環(huán)開始咧擂,拿出第一輪中第一個放入macro-task
列表中的事件開始執(zhí)行完畢
第二輪事件循環(huán)結(jié)束逞盆。
第三輪循環(huán)開始,拿出第一輪中第二個放入macro-task列表中的事件開始執(zhí)行完畢
第三輪事件循環(huán)結(jié)束松申。
就像上面這樣云芦,反復執(zhí)行,即事件循環(huán)贸桶。
看了上面的解釋舅逸,接下來,我們來看一個例子:
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')
})
})
我們按照上面的理論來分析這段代碼:
首先皇筛,進入到第一輪事件循環(huán):
遇到 console.log('1') 輸出 '1'
遇到 setTimeout琉历,將其回調(diào)函數(shù)加入到 macro-task
事件列表,記為 setTimeout1
遇到 process.nextTick水醋,將其回調(diào)函數(shù)加入到 micro-task
事件列表善已,記為 process1
遇到 new Promise,立即執(zhí)行离例,輸出 ** '7'**换团,then被分發(fā)到 micro-task
事件列表,記為 then1
遇到 setTimeout 將其回調(diào)函數(shù)加入到 macro-task
事件列表宫蛆,記為 setTimeout2
執(zhí)行到這里艘包,我們來數(shù)數(shù)第一輪事件循環(huán)中的任務(wù)列表:
macro-task:setTimeout1,setTimeout2
micro-task:process1, then1
將列表中所有的 micro-task 執(zhí)行完畢耀盗,輸出 '6','8'
第一輪事件循環(huán)正式結(jié)束想虎。
第二輪事件循環(huán)開始:
這時,第一輪輸出結(jié)果是 '1','7','6','8'
在 macro-task
中叛拷,拿出第一個進入的事件舌厨,即setTimeout1,將其推入到執(zhí)行棧開始執(zhí)行
先輸出:'2'
遇到 process.nextTick忿薇,將其回調(diào)函數(shù)加入到 micro-task
事件列表裙椭,記為 process2
遇到 new Promise躏哩, 立即執(zhí)行,輸出 ** '4'**揉燃,將then回調(diào)函數(shù)加入到 micro-task
事件列表扫尺,記為 then2
執(zhí)行到這里,我們數(shù)數(shù)第二輪事件循環(huán)中的任務(wù)列表:
macro-task:setTimeout1
micro-task:process2炊汤,then2
將列表中所有的 micro-task 執(zhí)行完畢正驻,輸出:'3', '5'
第二輪事件循環(huán)結(jié)束
第三輪事件循環(huán)開始,前兩輪輸出為:'1','7','6','8','2','4','3', '5'
在 macro-task 中抢腐,拿出第二個進入的事件姑曙,即setTimeout2,將其推入到執(zhí)行棧開始執(zhí)行
先輸出:'9'
遇到 process.nextTick迈倍,將其回調(diào)函數(shù)加入到 micro-task
事件列表伤靠,記為 process3
遇到 new Promise, 立即執(zhí)行授瘦,輸出 '11',將then回調(diào)函數(shù)加入到 micro-task
事件列表竟宋,記為 then3
執(zhí)行到這里提完,我們數(shù)數(shù)第三輪事件循環(huán)中的任務(wù)列表:
macro-task:setTimeout2
micro-task:process3,then3
將列表中所有的 micro-task
執(zhí)行完畢丘侠,輸出:'10', '12'
第三輪事件循環(huán)結(jié)束徒欣。
如果還有第四輪,第五輪蜗字,則循環(huán)上面的步驟打肝,這樣的循環(huán),即事件循環(huán)挪捕。
總結(jié)執(zhí)行結(jié)果:'1','7','6','8','2','4','3','5','9','11','10','12'
好粗梭,寫完收工,等待下班去吃大餐级零。
原文作者寫的更好断医,大家可以看看 https://juejin.im/post/59e85eebf265da430d571f89