瀏覽器的進程模型
先說結(jié)論:
隨著瀏覽器的復(fù)雜度急劇提升碟摆,W3C 不再使?宏隊列的說法
在?前 chrome 的實現(xiàn)中吩抓,?少包含了下?的隊列:
延時隊列:?于存放計時器到達后的回調(diào)任務(wù)试幽,優(yōu)先級「中」螟凭;
setTimeout,setInterval峡蟋,setImmediate([Node].js 環(huán)境)
交互隊列:?于存放?戶操作后產(chǎn)?的事件處理任務(wù)米罚,優(yōu)先級「?」钧汹;
onClick,onChange 等
微隊列:?戶存放需要最快執(zhí)?的任務(wù),優(yōu)先級「最?」录择;
Promise.then拔莱、MutationObserver、process.nextTick(Node.js 環(huán)境)
function a() {
console.log(1);
Promise.resolve().then(function () {
console.log(2);
});
}
setTimeout(function () {
console.log(3);
Promise.resolve().then(a);
}, 0);
Promise.resolve().then(function () {
console.log(4);
});
console.log(5);
//輸出 5,4,3,1,2
執(zhí)行順序:
渲染主進程執(zhí)行完之后
微任務(wù)隊列:promise.then(4)
交互任務(wù)隊列:
延遲任務(wù)隊列: setTimeout
輸出5
接著把微任務(wù)拿到主進程執(zhí)行
輸出4
微任務(wù)沒有了隘竭,看交互任務(wù)塘秦,沒有,把延遲任務(wù)拿到主進程執(zhí)行
輸出3 promise.then(函數(shù)a) 放到微任務(wù)
接著又把微任務(wù)拿到主進程執(zhí)行
輸出1动看,promise.then(2) 放到微任務(wù)
輸出2
function a() {
console.log(1);
Promise.resolve().then(function () {
console.log(2);
});
}
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(a);
console.log(5);
//輸出5,1,2,3
執(zhí)行順序:
渲染主進程執(zhí)行完之后
微任務(wù)隊列:promise.then(函數(shù)a)
交互任務(wù)隊列:
延遲任務(wù)隊列: setTimeout
輸出5
接著把微任務(wù)拿到主線程執(zhí)行
輸出1 promise.then(2)放到微任務(wù)
接著把微任務(wù)拿到主線程執(zhí)行
輸出2尊剔,微任務(wù)結(jié)束
接著把延遲任務(wù)拿到主線程執(zhí)行
輸出3
何為進程?
程序運?需要有它??專屬的內(nèi)存空間菱皆,可以把這塊內(nèi)存空間簡單的理解
每個應(yīng)??少有?個進程须误,進程之間相互獨?挨稿,即使要通信,也需要雙?
同意京痢。
何為線程奶甘?
有了進程后,就可以運?程序的代碼了祭椰。
運?代碼的「?」稱之為「線程」臭家。
?個進程?少有?個線程,所以在進程開啟后會?動創(chuàng)建?個線程來運?
代碼方淤,該線程稱之為主線程钉赁。
如果程序需要同時執(zhí)?多塊代碼,主線程就會啟動更多的線程來執(zhí)?代
碼携茂,所以?個進程中可以包含多個線程你踩。
瀏覽器有哪些進程和線程?
瀏覽器是?個多進程多線程的應(yīng)?程序
瀏覽器內(nèi)部?作極其復(fù)雜讳苦。
為了避免相互影響姓蜂,為了減少連環(huán)崩潰的?率,當(dāng)啟動瀏覽器后医吊,它會?
動啟動多個進程。
可以在瀏覽器的任務(wù)管理器中查看當(dāng)前的所有進程
其中逮京,最主要的進程有:
- 瀏覽器進程
主要負責(zé)界?顯示卿堂、?戶交互、?進程管理等懒棉。瀏覽器進程內(nèi)部會啟動多個
線程處理不同的任務(wù)草描。- ?絡(luò)進程
負責(zé)加載?絡(luò)資源。?絡(luò)進程內(nèi)部會啟動多個線程來處理不同的?絡(luò)任務(wù)策严。- 渲染進程
渲染進程啟動后穗慕,會開啟?個渲染主線程,主線程負責(zé)執(zhí)? HTML妻导、CSS逛绵、
JS 代碼。
默認情況下倔韭,瀏覽器會為每個標(biāo)簽?開啟?個新的渲染進程术浪,以保證不同的
標(biāo)簽?之間不相互影響。
渲染主線程是如何?作的寿酌?
渲染主線程是瀏覽器中最繁忙的線程胰苏,需要它處理的任務(wù)包括但不限于:
解析 HTML
解析 CSS
計算樣式
布局
處理圖層
每秒把??畫 60 次
執(zhí)?全局 JS 代碼
執(zhí)?事件處理函數(shù)
執(zhí)?計時器的回調(diào)函數(shù)
......
如何理解 JS 的異步?
JS是??單線程的語?醇疼,這是因為它運?在瀏覽器的渲染主線程中硕并,?渲染
主線程只有?個法焰。
?渲染主線程承擔(dān)著諸多的?作,渲染??倔毙、執(zhí)? JS 都在其中運?埃仪。
如果使?同步的?式,就極有可能導(dǎo)致主線程產(chǎn)?阻塞普监,從?導(dǎo)致消息隊列
中的很多其他任務(wù)?法得到執(zhí)?贵试。這樣?來甘桑,???會導(dǎo)致繁忙的主線程?
?的消耗時間碎节,另???導(dǎo)致???法及時更新混卵,給?戶造成卡死現(xiàn)象塘淑。
所以瀏覽器采?異步的?式來避免分苇。具體做法是當(dāng)某些任務(wù)發(fā)?時由桌,?如計
時器嬉探、?絡(luò)颠放、事件監(jiān)聽允睹,主線程將任務(wù)交給其他線程去處理运准,?身?即結(jié)束
任務(wù)的執(zhí)?,轉(zhuǎn)?執(zhí)?后續(xù)代碼缭受。當(dāng)其他線程完成時胁澳,將事先傳遞的回調(diào)函
數(shù)包裝成任務(wù),加?到消息隊列的末尾排隊米者,等待主線程調(diào)度執(zhí)?韭畸。
在這種異步模式下,瀏覽器永不阻塞蔓搞,從?最?限度的保證了單線程的流暢
運?胰丁。
任務(wù)有優(yōu)先級嗎?
任務(wù)沒有優(yōu)先級喂分,在消息隊列中先進先出
但消息隊列是有優(yōu)先級的
根據(jù) W3C 的最新解釋:
每個任務(wù)都有?個任務(wù)類型锦庸,同?個類型的任務(wù)必須在?個隊列,不同類型
的任務(wù)可以分屬于不同的隊列蒲祈。
在?次事件循環(huán)中甘萧,瀏覽器可以根據(jù)實際情況從不同的隊列中取出任務(wù)執(zhí)
?。
瀏覽器必須準(zhǔn)備好?個微隊列讳嘱,微隊列中的任務(wù)優(yōu)先所有其他任務(wù)執(zhí)?
https://html.spec.whatwg.org/multipage/webappapis.html#p
erform-a-microtask-checkpoint
隨著瀏覽器的復(fù)雜度急劇提升幔嗦,W3C 不再使?宏隊列的說法
在?前 chrome 的實現(xiàn)中,?少包含了下?的隊列:
延時隊列:?于存放計時器到達后的回調(diào)任務(wù)沥潭,優(yōu)先級「中」
交互隊列:?于存放?戶操作后產(chǎn)?的事件處理任務(wù)邀泉,優(yōu)先級「?」
微隊列:?戶存放需要最快執(zhí)?的任務(wù),優(yōu)先級「最?」
闡述?下 JS 的事件循環(huán)
事件循環(huán)?叫做消息循環(huán),是瀏覽器渲染主線程的?作?式汇恤。
在 Chrome 的源碼中庞钢,它開啟?個不會結(jié)束的 for 循環(huán),每次循環(huán)從消息
隊列中取出第?個任務(wù)執(zhí)?因谎,?其他線程只需要在合適的時候?qū)⑷蝿?wù)加?到
隊列末尾即可基括。
過去把消息隊列簡單分為宏隊列和微隊列,這種說法?前已?法滿?復(fù)雜的
瀏覽器環(huán)境财岔,取?代之的是?種更加靈活多變的處理?式风皿。
根據(jù) W3C 官?的解釋,每個任務(wù)有不同的類型匠璧,同類型的任務(wù)必須在同?
個隊列桐款,不同的任務(wù)可以屬于不同的隊列。不同任務(wù)隊列有不同的優(yōu)先級夷恍,
在?次事件循環(huán)中魔眨,由瀏覽器??決定取哪?個隊列的任務(wù)。但瀏覽器必須
有?個微隊列酿雪,微隊列的任務(wù)?定具有最?的優(yōu)先級遏暴,必須優(yōu)先調(diào)度執(zhí)?。
JS 中的計時器能做到精確計時嗎指黎?為什么朋凉?
不?,因為:
- 計算機硬件沒有原?鐘醋安,?法做到精確計時
- 操作系統(tǒng)的計時函數(shù)本身就有少量偏差侥啤,由于 JS 的計時器最終調(diào)?的
是操作系統(tǒng)的函數(shù),也就攜帶了這些偏差- 按照 W3C 的標(biāo)準(zhǔn)茬故,瀏覽器實現(xiàn)計時器時,如果嵌套層級超過 5 層蚁鳖,
則會帶有 4 毫秒的最少時間磺芭,這樣在計時時間少于 4 毫秒時?帶來
了偏差- 受事件循環(huán)的影響,計時器的回調(diào)函數(shù)只能在主線程空閑時運?醉箕,因此
?帶來了偏差