一句話解釋
js的主線程是單線程運行的,主線程先執(zhí)行同步代碼饶号,遇到異步操作如ajax請求、定時器等需要在一段時間后再執(zhí)行的事件璧亚,便交給其他線程如請求線程讨韭、定時觸發(fā)線程脂信,滿足條件后就放到任務隊列中癣蟋,主線程執(zhí)行完任務后透硝,就去任務隊列里拉取任務,按照先進先出的原則依次執(zhí)行疯搅,如此循環(huán)濒生;
其中任務隊列分為宏任務隊列與微任務隊列,執(zhí)行完一個宏任務都會去檢查是否有微任務幔欧,執(zhí)行完所有微任務后罪治,頁面更新渲染,再執(zhí)行下一個宏任務礁蔗;
問答
1.為什么JS是單線程的觉义?
- 防止同時操作同一DOM出現(xiàn)混亂。
- 所謂的"JS是單線程的"只是指JS的主運行線程只有一個浴井,而不是整個運行環(huán)境都是單線程晒骇。
2.JS單線程如何實現(xiàn)異步?
- JS異步的實現(xiàn)靠的就是瀏覽器的多線程磺浙,當遇到異步API時洪囤,就將這個任務交給對應的線程,當這個異步API滿足回調條件時撕氧,對應的線程又通過事件觸發(fā)線程將這個事件放入任務隊列瘤缩,然后主線程從任務隊列取出事件繼續(xù)執(zhí)行。
- JS引擎線程跟GUI線程是互斥的伦泥,一個執(zhí)行就另一個不執(zhí)行剥啤,如果JS長時間運行,GUI線程就不能執(zhí)行不脯,整個頁面就感覺卡死了府怯。
3.為什么要有微任務?
- 微任務是為了解決效率和實時性問題跨新,處理高優(yōu)先級的任務富腊。
4.常見的宏任務與微任務有哪些?
- 宏任務macrotask:script(整體代碼)域帐、setTimeout赘被、setInterval、setImmediate肖揣、I/O
- 微任務microtask:Promise民假、MutaionObserver、process.nextTick(Node)
5.瀏覽器什么時候渲染龙优?
- 執(zhí)行完一個宏任務以及當前所有微任務后渲染一次羊异;
- 但并不是每輪event loop都會更新渲染,這取決于是否修改了dom和瀏覽器覺得是否有必要在此時立即將新狀態(tài)呈現(xiàn)給用戶。如果在一幀的時間內(時間并不確定野舶,因為瀏覽器每秒的幀數(shù)總在波動易迹,16.7ms只是估算并不準確)修改了多處dom,瀏覽器可能將變動積攢起來平道,只進行一次繪制睹欲。
6.與Node環(huán)境的事件循環(huán)有什么區(qū)別?
瀏覽器和Node 環(huán)境下一屋,microtask 任務隊列的執(zhí)行時機不同:
- 瀏覽器端窘疮,microtask 在事件循環(huán)的 macrotask 執(zhí)行完之后執(zhí)行;
- Node版本>=11冀墨,和瀏覽器表現(xiàn)一致闸衫;
- Node版本<11,microtask 在事件循環(huán)的各個階段之間執(zhí)行诽嘉,也就是一個階段執(zhí)行完畢蔚出,就會去執(zhí)行microtask隊列的任務;
由于定時器插入時機不同含懊,同一代碼執(zhí)行結果也會不同,如下:
setTimeout(()=>{
console.log('timer1')
Promise.resolve().then(function() {
console.log('promise1')
})
}, 0)
setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
Node端分為6個階段岔乔,
- timers 階段:這個階段執(zhí)行timer(setTimeout酥筝、setInterval)的回調
- I/O callbacks 階段:處理一些上一輪循環(huán)中的少數(shù)未執(zhí)行的 I/O 回調
- idle, prepare 階段:僅node內部使用
- poll 階段:獲取新的I/O事件, 適當?shù)臈l件下node將阻塞在這里
- check 階段:執(zhí)行 setImmediate() 的回調
- close callbacks 階段:執(zhí)行 socket 的 close 事件回調
外部輸入數(shù)據(jù)-->輪詢階段(poll)-->檢查階段(check)-->關閉事件回調階段(close callback)-->定時器檢測階段(timer)-->I/O事件回調階段(I/O callbacks)-->閑置階段(idle, prepare)-->輪詢階段(按照該順序反復運行)