要搞懂這個(gè)問(wèn)題,首先要了解事件循環(huán)(Event Loop)
JS運(yùn)行時(shí),對(duì)代碼執(zhí)行順序的一個(gè)算法(任務(wù)調(diào)度算法)
JS 分類:同步任務(wù)和異步任務(wù)
JS 的執(zhí)行機(jī)制:
- 首先判斷JS代碼是同步還是異步,同步就進(jìn)入主線程,異步就進(jìn)入 event table
- 異步任務(wù)在 event table 中注冊(cè)函數(shù),當(dāng)滿足觸發(fā)條件后,被推入event queue
- 同步任務(wù)進(jìn)入主線程后一直執(zhí)行,直到主線程空閑時(shí),才回去 event queue 中查看是否有可執(zhí)行的異步任務(wù),如果有就推入主線程
event loop 里有維護(hù)兩個(gè)不同的異步任務(wù)隊(duì)列
- macro Tasks(宏任務(wù)):script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
- micro Tasks(微任務(wù)):process.nextTick, Promise(瀏覽器實(shí)現(xiàn)的原生Promise), Object.observe, MutationObserver, MessageChannel
每次執(zhí)行一段代碼(一個(gè)script標(biāo)簽)都是一個(gè) macroTask
執(zhí)行流程:
- event loop 開始
- 從macro Tasks 隊(duì)列抽取一個(gè)任務(wù),執(zhí)行
- micro Tasks 清空隊(duì)列執(zhí)行,若有任務(wù)不可執(zhí)行,推入下一輪 micro Tasks
- 結(jié)束 event loop
瀏覽器執(zhí)行代碼的過(guò)程如下整個(gè)流程

image
那么回到題目上去,就是
setTimeout(function(){
console.log(1); // 1-放入宏任務(wù)隊(duì)列,7-執(zhí)行下一輪事件循環(huán),宏任務(wù)輸出1
},0);
new Promise(function(resolve) {
console.log(2); // 2-同步輸出 2
for(let i=0; i<10000 ; i++ ) {
i==9999 && resolve();
}
console.log(3); // 4-同步輸出 3
}).then(function(){
console.log(4); // 3-放入微任務(wù)隊(duì)列,6-回到微任務(wù)隊(duì)列,執(zhí)行剩余的微任務(wù),輸出4
});
console.log(5); // 5-同步輸出 5
作者:FunnyZ
經(jīng)典前端面試題每日更新,歡迎參與討論,地址:https://github.com/daily-interview/fe-interview。
更多angular1/2/4/5、ionic1/2/3、react、vue、微信小程序、nodejs等技術(shù)文章、視頻教程和開源項(xiàng)目,請(qǐng)關(guān)注微信公眾號(hào)——全棧弄潮兒。

image