前言
為能更好的理解瀏覽器性能優(yōu)化,本文會(huì)從瀏覽器多進(jìn)程架構(gòu)以及瀏覽器渲染過程逐步簡(jiǎn)單解析性能優(yōu)化要點(diǎn)
瀏覽器的多進(jìn)程架構(gòu)
進(jìn)程與線程
進(jìn)程類似于一個(gè)工廠宝磨,工廠擁有獨(dú)立的資源且相互獨(dú)立
線程類似于工廠中的工人忘闻,多個(gè)工人協(xié)作完成任務(wù)且相互共享空間
簡(jiǎn)單理解:
????進(jìn)程是cpu資源分配的最小單位,系統(tǒng)會(huì)為其分配內(nèi)存
????線程是cpu調(diào)度的最小單位,一個(gè)進(jìn)程中可擁有一個(gè)或多個(gè)線程
????不同進(jìn)程之間也可以進(jìn)行通信但是代價(jià)較大
瀏覽器多進(jìn)程
簡(jiǎn)單理解:
? ? 瀏覽器是多進(jìn)程的
????瀏覽器之所以能夠運(yùn)行是因?yàn)橄到y(tǒng)為其進(jìn)程分配了cpu于內(nèi)存資源
????基本上每打開一個(gè)Tab頁就相當(dāng)于創(chuàng)建了一個(gè)獨(dú)立的瀏覽器進(jìn)程
注:瀏覽器有自身的優(yōu)化機(jī)制,打開多個(gè)tab頁后部分tab頁的進(jìn)程會(huì)被合并(例如多個(gè)空白頁合并)
為什么瀏覽器是多進(jìn)程的(主要原因)
想象如果瀏覽器是單線程的元暴,某個(gè)Tab頁或是插件腳本崩潰了就會(huì)影響到整個(gè)瀏覽器,所以瀏覽器為保證穩(wěn)定性設(shè)計(jì)為多進(jìn)程
瀏覽器包含哪些主要進(jìn)程
1. Browser進(jìn)程:瀏覽器的主控進(jìn)程兄猩,只有一個(gè)
????負(fù)責(zé)瀏覽器界面顯示茉盏,與用戶交互
????負(fù)責(zé)各個(gè)頁面的管理,創(chuàng)建或銷毀其他進(jìn)程
????將瀏覽器渲染進(jìn)程存放在內(nèi)存中的bitmap(位圖)繪制到用戶界面上
????網(wǎng)絡(luò)資源的管理枢冤,下載等
2. 第三方插件進(jìn)程:每種類型的插件對(duì)應(yīng)一個(gè)進(jìn)程援岩,使用插件時(shí)才創(chuàng)建
3. GPU進(jìn)程:最多存在一個(gè),用于3D繪制
4. 瀏覽器渲染進(jìn)程(Renderer進(jìn)程):該進(jìn)程內(nèi)部為多線程掏导,默認(rèn)每個(gè)Tab頁面一個(gè)進(jìn)程,互不影響
? ?頁面渲染羽峰,腳本執(zhí)行趟咆,事件處理等
細(xì)化瀏覽器渲染進(jìn)程
瀏覽器中頁面的渲染,js的執(zhí)行梅屉,事件循環(huán)等都在該進(jìn)程中執(zhí)行值纱,其中包含多個(gè)線程
1. GUI渲染線程
????該線程負(fù)責(zé)渲染頁面,解析HTML于CSS坯汤,并構(gòu)建DOM樹并生成RenderObject樹
????單頁面需要重繪或是因?yàn)槟承┎僮骰亓鲿r(shí)虐唠,該線程就會(huì)執(zhí)行
????注:為保證不會(huì)因?yàn)殇秩緯r(shí)改變DOM導(dǎo)致的頁面錯(cuò)亂,GUI渲染線程與JS線程是互斥的
2. JS引擎線程
????其為JS內(nèi)核惰聂,負(fù)責(zé)處理JS腳本語言(V8引擎)
????一個(gè)Tab頁(renderer進(jìn)程)中無論什么時(shí)候都只有一個(gè)JS線程在運(yùn)行JS程序
3. 事件觸發(fā)線程
????其歸屬于瀏覽器用于處理被觸發(fā)的事件并將其回調(diào)函數(shù)放置于任務(wù)隊(duì)列中疆偿,待JS主執(zhí)行棧空時(shí)按一定規(guī)則執(zhí)行任務(wù)隊(duì)列中的回調(diào)函數(shù)
4. 定時(shí)器觸發(fā)線程
????用于處理setTimeout或是setInterval
5. 異步HTTP請(qǐng)求線程
????用于處理頁面中存在的異步HTTP請(qǐng)求搓幌,并將回調(diào)放入事件隊(duì)列中杆故,最后由js引擎執(zhí)行
頁面構(gòu)建過程
瀏覽器處理部分
開啟進(jìn)程存放頁面
????進(jìn)程中包含
????????GUI渲染線程:用于獲取到HTML后進(jìn)行頁面的構(gòu)建與渲染
????????JS引擎線程:用于處理頁面中的JS代碼,每個(gè)瀏覽器進(jìn)程都有一個(gè)
????????事件處理線程:用于處理用戶觸發(fā)事件產(chǎn)生的回調(diào)函數(shù)
????????HTTP處理線程:用于處理HTTP請(qǐng)求
????????定時(shí)器觸發(fā)線程:用于處理頁面中生成的定時(shí)器溉愁,并在合適的時(shí)候?qū)⒒卣{(diào)交由任務(wù)隊(duì)列
注:為保證數(shù)據(jù)與視圖的統(tǒng)一性处铛,GUI線程與JS線程存在互斥關(guān)系
構(gòu)建流程(GUI渲染線程)
1. 瀏覽器開始逐行解析HTML并開始創(chuàng)建DOM樹,DOM樹的創(chuàng)建是一個(gè)深度遍歷的過程拐揭,當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)構(gòu)建完成后才會(huì)構(gòu)建當(dāng)前節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)撤蟆,此時(shí)的document.readyState="loading"
2. 如果遇到外聯(lián)JS文件且沒有設(shè)置異步執(zhí)行則立即下載并同步執(zhí)行,遇到CSS文件則立即下載并生成CSSOM
3. HTML解析完成后將完整DOM樹與CSSOM結(jié)合生成渲染樹RenderTree堂污,此時(shí)的document.readyState="interaction"
渲染流程
1. RenderTree是由與DOM節(jié)點(diǎn)一一對(duì)應(yīng)的渲染對(duì)象RenderObject組成的家肯,其包含了節(jié)點(diǎn)信息以及渲染上下文
2. 處于相同坐標(biāo)空間的渲染對(duì)象都會(huì)歸并到一個(gè)渲染層中,對(duì)于形成層疊上下文的渲染對(duì)象會(huì)自動(dòng)為其創(chuàng)建新的渲染層盟猖,渲染對(duì)象自動(dòng)從屬于父元素最近的渲染層息楔,常見生成渲染層的方式
????根元素document
????postion: relative/absolute/fixed/sticky
????opacity < 1
????存在CSS fliter屬性
????存在CSS transform屬性
3. 在渲染層的基礎(chǔ)上滿足特定條件后該渲染層會(huì)被提升為合成層(圖形層)寝贡,擁有單獨(dú)的圖形上下文(相當(dāng)于進(jìn)行單獨(dú)渲染),其余不是合成層的渲染層和第一個(gè)擁有圖形上下文的父層共用一個(gè)合成層值依,合成層通常為經(jīng)常變動(dòng)的效果
????3Dtransforms: translate3D/translateZ
????video/canvas/iframe
????CSS動(dòng)畫實(shí)現(xiàn)的opacity動(dòng)畫轉(zhuǎn)換
????position:fixed
????will-change
????對(duì)opacity/transform/fliter應(yīng)用了transition或animation
????使用了裁剪(Clip)或者反射(Reflection)
注:將渲染層提升為合成層會(huì)帶有GPU加速效果圃泡,但是不能濫用
4. 得到各層后瀏覽器會(huì)計(jì)算出各層在頁面中的位置(回流)并調(diào)用其繪圖上下文進(jìn)行繪制渲染尝丐,最終呈現(xiàn)出整個(gè)頁面
隱式合成與層爆炸触创、層壓縮
若一個(gè)或多個(gè)非合成元素堆疊在合成層元素上,這些非合成層元素就會(huì)被提升成合成層假颇,從而出現(xiàn)隱式合成
層爆炸指產(chǎn)生的合成層太多導(dǎo)致大量占用GPU與內(nèi)存資源辆亏,進(jìn)而導(dǎo)致頁面卡頓或閃爍的現(xiàn)象风秤;其解決方法是提高合成層的z-index從而避免層疊來消除隱式合成
層壓縮是瀏覽器自身優(yōu)化機(jī)制,會(huì)將隱式合成產(chǎn)生的多余堆疊合成層壓縮為一個(gè)合成層扮叨,從而大大減少合成層的數(shù)量缤弦,降低GPU與內(nèi)存消耗
層合成規(guī)則的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
????層合成產(chǎn)生的位圖會(huì)交由GPU進(jìn)行單獨(dú)處理,其處理速度比CPU快
????需要重繪是只需重繪其自身不影響其他層
????元素提升為合成層后transform或是opacity的改變部觸發(fā)重繪
缺點(diǎn)
????合成層過多導(dǎo)致GPU占用過高彻磁,容易出現(xiàn)頁面閃爍
????隱式合成產(chǎn)生過多的合成層碍沐,會(huì)占用過多的資源
優(yōu)化方式
????動(dòng)畫使用transform實(shí)現(xiàn)
????減少隱式合成,動(dòng)畫節(jié)點(diǎn)設(shè)置高z-index
????減小合成層的尺寸衷蜓,可以使用scale放大累提,節(jié)省性能
重繪與回流
重繪:尺寸與布局不發(fā)生改變,僅改變部分樣式
回流:頁面中元素的尺寸與布局發(fā)生變化(合成層除外)
重繪不一定回流磁浇,回流一定重繪
引起回流的操作
????頁面初始渲染
????改變字體或元素的尺寸
????改變?cè)氐目梢妰?nèi)容
????增刪DOM元素
????fixed的元素滾動(dòng)時(shí)會(huì)一直回流
????調(diào)整窗口大小
????訪問offsetWidth或是offsetHeight等破壞flush隊(duì)列的操作
flush隊(duì)列
為性能優(yōu)化考慮斋陪,瀏覽器自身會(huì)維護(hù)一個(gè)flush隊(duì)列,該隊(duì)列存儲(chǔ)著回流的內(nèi)容置吓,每經(jīng)過一段時(shí)間或該隊(duì)列達(dá)到一定長度后瀏覽器就會(huì)一次性將其全部回流完成无虚,實(shí)現(xiàn)優(yōu)化性能的目的。但當(dāng)開發(fā)者訪問offsetwidth衍锚,offsetheight骑科,width,height等屬性時(shí)构拳,瀏覽器為了給開發(fā)者返回該元素準(zhǔn)確的值會(huì)破壞flush隊(duì)列咆爽,致使瀏覽器自身優(yōu)化失效
頁面優(yōu)化性能方法
代碼層面
元素位置變換時(shí)盡量使用css3的transfrom來代替top left的操作,因?yàn)樽儞Q僅僅影響圖層的組合位置
????使用opacity來代替visibility置森,因?yàn)橥该鞫炔⒉挥|發(fā)重繪
????????注:透明度改變時(shí)GPU在繪畫時(shí)只是簡(jiǎn)單的降低之前畫好紋理的alpha值來達(dá)到效果
????將多次class樣式改變操作合并為一次(預(yù)先定義改變后的class)
????使用display:none將dom元素離線后修改
????利用文檔碎片documentFragment收集短時(shí)間內(nèi)回流元素后一次回流添加到頁面(vue同款優(yōu)化)
????動(dòng)畫實(shí)現(xiàn)過程中使用transfrom:tranleteZ(0)使其提升為合成層通過GPU單獨(dú)渲染
????為動(dòng)畫元素新建圖層并提高其z-index以減少隱式合成
????減少對(duì)flush隊(duì)列的訪問斗埂,盡量不要破壞瀏覽器自身優(yōu)化
????單調(diào)色塊可使用合成層優(yōu)化中的scale縮放來優(yōu)化內(nèi)存占用
????CSS在上JS在下,觸發(fā)瀏覽器的first paint且減少同步代碼阻塞渲染的機(jī)率
資源層面
????除首屏展示外其余資源(圖片凫海、組件呛凶、視頻等)懶加載
????首屏中包含的視頻可以進(jìn)行分割傳輸
????單調(diào)圖片過大導(dǎo)致性能問題時(shí)可使用canvas或是svg繪圖
????對(duì)HTML、JS行贪、CSS資源進(jìn)行壓縮漾稀,服務(wù)器開啟Gzip
????對(duì)靜態(tài)資源使用緩存
????使用CDN縮短用戶與資源的距離? ? *? 升級(jí)到HTTP2使資源可以享受二進(jìn)制傳輸模闲、首部壓縮、多路復(fù)用