記憶核心:
JS 執(zhí)行一段腳本
- 同步任務(wù)在JS主線程(屬于渲染進(jìn)程的線程)執(zhí)行
- 異步任務(wù)進(jìn)入任務(wù)隊(duì)列(由事件觸發(fā)線程維護(hù))
- 同步任務(wù)執(zhí)行完壳快,渲染進(jìn)程的事件觸發(fā)線程將任務(wù)推送到JS主線程昙篙,執(zhí)行
不斷循環(huán)!!物赶!
瀏覽器進(jìn)程:
1.瀏覽器進(jìn)程(Browser進(jìn)程):瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào),主控),只有一個(gè)
1)負(fù)責(zé)瀏覽器的界面界面顯示捐迫,與用戶交互,網(wǎng)址欄輸入爱葵、前進(jìn)施戴、后退等
2)負(fù)責(zé)管理各個(gè)頁(yè)面,創(chuàng)建和銷毀進(jìn)程
3)將頁(yè)面內(nèi)容(位圖)寫入到瀏覽器內(nèi)存中萌丈,最后將圖像顯示在屏幕上
4)文件存儲(chǔ)等功能
2. ??? 渲染進(jìn)程(瀏覽器內(nèi)核赞哗,Renderer進(jìn)程,內(nèi)部是多線程的):默認(rèn)一個(gè)tab頁(yè)面一個(gè)渲染進(jìn)程(特殊情況下:渲染進(jìn)程不一定每個(gè)tab就一個(gè))辆雾,主要的作用為頁(yè)面渲染肪笋,腳本執(zhí)行,事件處理等
3.GPU進(jìn)程:用于3D繪制等,將開啟了3D繪制的元素的渲染由CPU轉(zhuǎn)向GPU涂乌,也就是開啟GPU加速艺栈。最多一個(gè)
4.網(wǎng)絡(luò)進(jìn)程:主要負(fù)責(zé)頁(yè)面的網(wǎng)絡(luò)資源加載,之前是作為一個(gè)模塊運(yùn)行在瀏覽器進(jìn)程里面湾盒,現(xiàn)在獨(dú)立開來(lái)湿右,成為一個(gè)單獨(dú)的進(jìn)程
5.插件進(jìn)程:每種類型的插件對(duì)應(yīng)一個(gè)進(jìn)程,僅當(dāng)使用該插件時(shí)才創(chuàng)建
6.音頻進(jìn)程:瀏覽器音頻管理
渲染進(jìn)程中的線程
說(shuō)到事件循環(huán)罚勾,主角就是在講渲染進(jìn)程中的線程
渲染進(jìn)程中主要都包含了哪些線程毅人?
1.GUI渲染線程
1)負(fù)責(zé)渲染瀏覽器界面,解析HTML尖殃,CSS丈莺,構(gòu)建DOM樹和RenderObject樹,布局和繪制
2)當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時(shí)送丰,該線程就會(huì)執(zhí)行
3)與JS引擎互斥缔俄,當(dāng)執(zhí)行JS引擎線程時(shí),GUI會(huì)pending器躏,當(dāng)任務(wù)隊(duì)列空閑時(shí)俐载,才會(huì)繼續(xù)執(zhí)行GUI
2.JS引擎線程(執(zhí)行JS)
1)也稱為JS內(nèi)核,負(fù)責(zé)處理javascript腳本程序
2)JS引擎線程負(fù)責(zé)解析Javascript腳本登失,運(yùn)行代碼
3)JS引擎一直等待任務(wù)隊(duì)列中任務(wù)的到來(lái)遏佣,然后加以處理,瀏覽器無(wú)論什么時(shí)候都只有一個(gè)JS線程在運(yùn)行JS程序
4)同樣注意揽浙,GUI渲染線程與JS引擎線程時(shí)互斥的状婶,所以如果JS執(zhí)行的時(shí)間過(guò)長(zhǎng),這樣就會(huì)造成頁(yè)面的渲染不連貫馅巷,導(dǎo)致頁(yè)面渲染加載阻塞膛虫。
3.事件觸發(fā)線程(維護(hù)事件隊(duì)列)
1)事件觸發(fā)線程歸屬于瀏覽器而不是JS引擎(輔助JS引擎),用來(lái)控制事件循環(huán)(存在一個(gè)事件隊(duì)列)
2)當(dāng)JS引擎執(zhí)行代碼塊如setTimeOut時(shí)(也可來(lái)自瀏覽器內(nèi)核的其他線程令杈,如鼠標(biāo)點(diǎn)擊走敌,Ajax異步請(qǐng)求等),會(huì)將對(duì)應(yīng)的任務(wù)添加到事件線程中
3)當(dāng)對(duì)應(yīng)的事件符合觸發(fā)條件被觸發(fā)時(shí)逗噩,該線程會(huì)把事件添加到待處理隊(duì)列的隊(duì)尾,等待JS引擎的處理
4)注意跌榔,由于JS的單線程關(guān)系异雁,所以這些待處理隊(duì)列的事件都得排隊(duì)等待JS引擎的處理(當(dāng)JS引擎空閑時(shí)才會(huì)去執(zhí)行)
4.定時(shí)觸發(fā)器線程
1)setInterval、setTimeOut所在線程
2)瀏覽器定時(shí)計(jì)數(shù)器并不是由JavaScript引擎計(jì)數(shù)的僧须,(因?yàn)镴avaScript引擎時(shí)單線程的纲刀,如果處于阻塞線程狀態(tài)就會(huì)影響計(jì)時(shí)的準(zhǔn)確)
3)因此通過(guò)單獨(dú)線程來(lái)計(jì)時(shí)并觸發(fā)(計(jì)時(shí)完畢后,添加到事件隊(duì)列中担平,等待JS引擎空閑后執(zhí)行)
4)注意示绊,W3C在HTML標(biāo)準(zhǔn)中規(guī)定要求setTimeOut中低于4ms的時(shí)間間隔為4ms
5.異步HTTP請(qǐng)求線程(IO線程)
1)在XMLHttpRequest在連接后是通過(guò)瀏覽器新開一個(gè)線程請(qǐng)求
2)將檢測(cè)到狀態(tài)變更時(shí)锭部,如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件面褐,將這個(gè)回調(diào)再放入事件隊(duì)列中(放入事件觸發(fā)線程中)拌禾。再由JavaScript引擎執(zhí)行。
由上面概念得知:
- 瀏覽器是 多進(jìn)程展哭,單線程 的湃窍。
- js執(zhí)行的主線程為JS引擎,并且無(wú)論何時(shí)都 只有一個(gè)JS線程在運(yùn)行匪傍,所以是單線程執(zhí)行您市。
- GUI渲染線程和JS引擎線程是互斥的,并且JS會(huì)阻塞頁(yè)面的加載和渲染役衡。
- 定時(shí)器(setInterval,setTimeout)會(huì) 在定時(shí)器觸發(fā)器線程中進(jìn)行計(jì)時(shí)茵休。
- 定時(shí)觸發(fā)器線程計(jì)時(shí)結(jié)束后需要執(zhí)行的事件和異步HTTP請(qǐng)求線程的 回調(diào)事件都會(huì)進(jìn)入到事件觸發(fā)線程的任務(wù)隊(duì)列 中等待 JS引擎的執(zhí)行
瀏覽器的事件循環(huán)
JS執(zhí)行:
- 同步任務(wù)在JS主線程(屬于渲染進(jìn)程的線程)執(zhí)行
- 異步任務(wù)進(jìn)入任務(wù)隊(duì)列(由事件觸發(fā)線程維護(hù))
- 同步任務(wù)執(zhí)行完,渲染進(jìn)程的事件觸發(fā)線程將任務(wù)推送到JS主線程手蝎,執(zhí)行
不斷循環(huán)i泡骸!柑船!
宏任務(wù) / 微任務(wù)
ES6中新增了Promise和process.nextTick(callback)帽撑。于是我們?cè)趶V義的同步任務(wù)和異步任務(wù)中,對(duì)任務(wù)有了更細(xì)致的劃分:
- macro-task(宏任務(wù)):包括整體代碼script鞍时,setTimeout亏拉,setInterval
- micro-task(微任務(wù)):Promise,process.nextTick
宏任務(wù)逆巍,可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個(gè)宏任務(wù)(包括主線程執(zhí)行的同步任務(wù)和每次從事件隊(duì)列中獲取并放到執(zhí)行棧中去執(zhí)行的異步任務(wù))及塘。
在任務(wù)隊(duì)列 中其實(shí)還分為宏任務(wù)隊(duì)列和微任務(wù)隊(duì)列!
完整的執(zhí)行順序
- 從上往下執(zhí)行所有的同步代碼
- 在執(zhí)行過(guò)程中遇到宏任務(wù)就存放到宏任務(wù)隊(duì)列中, 遇到微任務(wù)就存放到微任務(wù)隊(duì)列中
- 當(dāng)所有的同步任務(wù)執(zhí)行完畢, 就執(zhí)行微任務(wù)隊(duì)列中滿足需求的所有回調(diào)( process.nextTick 優(yōu)先 )
- 當(dāng)微任務(wù)隊(duì)列中所有滿足需求的回調(diào)執(zhí)行完畢后, 就執(zhí)行宏任務(wù)隊(duì)列中滿足需求的所有回調(diào) ( SetImmediate 最后 )
微任務(wù)隊(duì)列先執(zhí)行锐极!