深入理解事件循环机制
瀏覽器常駐的線程
- js引擎線程(解釋執(zhí)行js代碼、用戶輸入、網(wǎng)絡(luò)請求)
- GUI線程(繪制用戶界面、與js主線程是互斥的)
- http網(wǎng)絡(luò)請求線程(處理用戶的get,post等請求,等返回結(jié)果后將回調(diào)函數(shù)推入任務(wù)隊列)
- 定時器觸發(fā)線程(setTimeout,setIntervat等待事件結(jié)束后把執(zhí)行函數(shù)推入任務(wù)隊列中)
- 瀏覽器事件處理線程(將click,mouse等交互事件發(fā)生后將這些事件放入事件隊列中)
UI主線程負(fù)責(zé)協(xié)調(diào)運轉(zhuǎn)
【例】當(dāng)js引擎是單線程的,若當(dāng)前執(zhí)行的函數(shù)快沒有處理完,不會執(zhí)行下一個函數(shù)塊,此處寫一個死循環(huán)去證明該點
<body><button id="btn">run</button> </body> <script type="text/javascript"> var oBtn = document.getElementById('btn'); function dieLoop() {while (true) {} } oBtn.onclick = function () {console.log("a"); } </script>【結(jié)果】點擊按鈕打印"a",執(zhí)行函數(shù)dieLoop(作死的人才去執(zhí)行這個函數(shù),反正我卡死了),再點擊按鈕,不執(zhí)行該點擊事件
JS引擎線程和GUI線程—互斥
JS可以操作DOM元素,進而會影響到GUI的渲染結(jié)果因此JS引擎線程與GU渲染線程是互斥的。也就是說當(dāng)JS引擎線程處于運行狀態(tài)時,GUI渲染線程將處于凍結(jié)狀態(tài)。
JS執(zhí)行機制
- 單線程—同一時間只能做一件事
- 使用單線程的原因:js設(shè)計出來就是為了與用戶交互,處理DOM,假如js是多線程,同一時間一個線程想要修改DOM,另一個線程想要刪除DOM,問題就變得復(fù)雜許多,問題就變得復(fù)雜,如果引入“鎖”的機制,就回到了被其他語言尷尬的困境(什么被其他語言尷尬的困境?)
- 操作大量數(shù)據(jù)的解決辦法:單線程計算能力有限,大量數(shù)據(jù)需要計算渲染的話,需要配合后端進行操作(VUE和node.js配合,即SSR技術(shù))
- 異步執(zhí)行:JAvaScript是基于單線程運行的,同時又可以異步執(zhí)行,一般來說這種既是單線程又是異步的語言都是基于事件來驅(qū)動的,恰好瀏覽器給JavaScript提供了這樣的環(huán)境
- 流程圖如下
解釋:
- 同步和異步任務(wù)分別進入不同的執(zhí)行“場所”,同步的進入主線程,異步的進入Event Table并注冊函數(shù)
- 當(dāng)指定的事情完成時,Event Table會將這個函數(shù)移入Event Queue
- 主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會去Event Queue讀取對應(yīng)的函數(shù),進入主線程執(zhí)行,
- 上述過程不斷重復(fù),即Event Loop(事件循環(huán))
同步任務(wù)
【例】
function foo(ot) {function bar(it) {debugger;console.log(it);}bar(10);console.log(ot); } foo(20);【結(jié)果】
【分析】
異步任務(wù)
【例】
$.ajax({url : '',data : {},success : function (data) {console.log(data);} }); console.log('run');【分析】
深入理解定時器
setTimeout的等待事件結(jié)束后并不是直接執(zhí)行的,而是先推入瀏覽器的一個任務(wù)隊列,在同步隊列結(jié)束后,再依次調(diào)用任務(wù)隊列中的任務(wù)
setTimeout(function(){},0)實際上,就算JS主線程中的執(zhí)行棧為空,也達(dá)不到0毫秒,根據(jù)HTML標(biāo)準(zhǔn),最低4毫秒
setInterval是每隔一段時間把任務(wù)放到Event Queue之中
【例】
var firstTime = + new Date(); function loop(d) {for (var i = 0; i < d; i++) {console.log(i);} } loop(10000); setTimeout(function () {var time = + new Date() - firstTime;console.log(time); },100);【結(jié)果】
【分析】setTimeout并不是100毫秒之后執(zhí)行的,而是100毫秒后放入任務(wù)隊列,在同步隊列的任務(wù)執(zhí)行完畢后,執(zhí)行任務(wù)隊列的setTimeout。
總結(jié)
以上是生活随笔為你收集整理的深入理解事件循环机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 响应式原理
- 下一篇: bootstrap内容部分API解读(1