前言
為能更好的理解瀏覽器性能優化,本文會從瀏覽器多進程架構以及瀏覽器渲染過程逐步簡單解析性能優化要點
瀏覽器的多進程架構
進程與線程
進程類似于一個工廠,工廠擁有獨立的資源且相互獨立
線程類似于工廠中的工人,多個工人協作完成任務且相互共享空間
簡單理解:
????進程是cpu資源分配的最小單位,系統會為其分配內存
????線程是cpu調度的最小單位,一個進程中可擁有一個或多個線程
????不同進程之間也可以進行通信但是代價較大
瀏覽器多進程
簡單理解:
? ? 瀏覽器是多進程的
????瀏覽器之所以能夠運行是因為系統為其進程分配了cpu于內存資源
????基本上每打開一個Tab頁就相當于創建了一個獨立的瀏覽器進程
注:瀏覽器有自身的優化機制,打開多個tab頁后部分tab頁的進程會被合并(例如多個空白頁合并)
為什么瀏覽器是多進程的(主要原因)
想象如果瀏覽器是單線程的,某個Tab頁或是插件腳本崩潰了就會影響到整個瀏覽器,所以瀏覽器為保證穩定性設計為多進程
瀏覽器包含哪些主要進程
1. Browser進程:瀏覽器的主控進程,只有一個
????負責瀏覽器界面顯示,與用戶交互
????負責各個頁面的管理,創建或銷毀其他進程
????將瀏覽器渲染進程存放在內存中的bitmap(位圖)繪制到用戶界面上
????網絡資源的管理,下載等
2. 第三方插件進程:每種類型的插件對應一個進程,使用插件時才創建
3. GPU進程:最多存在一個,用于3D繪制
4. 瀏覽器渲染進程(Renderer進程):該進程內部為多線程,默認每個Tab頁面一個進程,互不影響
? ?頁面渲染,腳本執行,事件處理等
細化瀏覽器渲染進程
瀏覽器中頁面的渲染,js的執行,事件循環等都在該進程中執行,其中包含多個線程
1. GUI渲染線程
????該線程負責渲染頁面,解析HTML于CSS,并構建DOM樹并生成RenderObject樹
????單頁面需要重繪或是因為某些操作回流時,該線程就會執行
????注:為保證不會因為渲染時改變DOM導致的頁面錯亂,GUI渲染線程與JS線程是互斥的
2. JS引擎線程
????其為JS內核,負責處理JS腳本語言(V8引擎)
????一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
3. 事件觸發線程
????其歸屬于瀏覽器用于處理被觸發的事件并將其回調函數放置于任務隊列中,待JS主執行棧空時按一定規則執行任務隊列中的回調函數
4. 定時器觸發線程
????用于處理setTimeout或是setInterval
5. 異步HTTP請求線程
????用于處理頁面中存在的異步HTTP請求,并將回調放入事件隊列中,最后由js引擎執行
頁面構建過程
瀏覽器處理部分
開啟進程存放頁面
????進程中包含
????????GUI渲染線程:用于獲取到HTML后進行頁面的構建與渲染
????????JS引擎線程:用于處理頁面中的JS代碼,每個瀏覽器進程都有一個
????????事件處理線程:用于處理用戶觸發事件產生的回調函數
????????HTTP處理線程:用于處理HTTP請求
????????定時器觸發線程:用于處理頁面中生成的定時器,并在合適的時候將回調交由任務隊列
注:為保證數據與視圖的統一性,GUI線程與JS線程存在互斥關系
構建流程(GUI渲染線程)
1. 瀏覽器開始逐行解析HTML并開始創建DOM樹,DOM樹的創建是一個深度遍歷的過程,當前節點的所有子節點構建完成后才會構建當前節點的下一個兄弟節點,此時的document.readyState="loading"
2. 如果遇到外聯JS文件且沒有設置異步執行則立即下載并同步執行,遇到CSS文件則立即下載并生成CSSOM
3. HTML解析完成后將完整DOM樹與CSSOM結合生成渲染樹RenderTree,此時的document.readyState="interaction"
渲染流程
1. RenderTree是由與DOM節點一一對應的渲染對象RenderObject組成的,其包含了節點信息以及渲染上下文
2. 處于相同坐標空間的渲染對象都會歸并到一個渲染層中,對于形成層疊上下文的渲染對象會自動為其創建新的渲染層,渲染對象自動從屬于父元素最近的渲染層,常見生成渲染層的方式
????根元素document
????postion: relative/absolute/fixed/sticky
????opacity < 1
????存在CSS fliter屬性
????存在CSS transform屬性
3. 在渲染層的基礎上滿足特定條件后該渲染層會被提升為合成層(圖形層),擁有單獨的圖形上下文(相當于進行單獨渲染),其余不是合成層的渲染層和第一個擁有圖形上下文的父層共用一個合成層,合成層通常為經常變動的效果
????3Dtransforms: translate3D/translateZ
????video/canvas/iframe
????CSS動畫實現的opacity動畫轉換
????position:fixed
????will-change
????對opacity/transform/fliter應用了transition或animation
????使用了裁剪(Clip)或者反射(Reflection)
注:將渲染層提升為合成層會帶有GPU加速效果,但是不能濫用
4. 得到各層后瀏覽器會計算出各層在頁面中的位置(回流)并調用其繪圖上下文進行繪制渲染,最終呈現出整個頁面
隱式合成與層爆炸、層壓縮
若一個或多個非合成元素堆疊在合成層元素上,這些非合成層元素就會被提升成合成層,從而出現隱式合成
層爆炸指產生的合成層太多導致大量占用GPU與內存資源,進而導致頁面卡頓或閃爍的現象;其解決方法是提高合成層的z-index從而避免層疊來消除隱式合成
層壓縮是瀏覽器自身優化機制,會將隱式合成產生的多余堆疊合成層壓縮為一個合成層,從而大大減少合成層的數量,降低GPU與內存消耗
層合成規則的優缺點
優點
????層合成產生的位圖會交由GPU進行單獨處理,其處理速度比CPU快
????需要重繪是只需重繪其自身不影響其他層
????元素提升為合成層后transform或是opacity的改變部觸發重繪
缺點
????合成層過多導致GPU占用過高,容易出現頁面閃爍
????隱式合成產生過多的合成層,會占用過多的資源
優化方式
????動畫使用transform實現
????減少隱式合成,動畫節點設置高z-index
????減小合成層的尺寸,可以使用scale放大,節省性能
重繪與回流
重繪:尺寸與布局不發生改變,僅改變部分樣式
回流:頁面中元素的尺寸與布局發生變化(合成層除外)
重繪不一定回流,回流一定重繪
引起回流的操作
????頁面初始渲染
????改變字體或元素的尺寸
????改變元素的可見內容
????增刪DOM元素
????fixed的元素滾動時會一直回流
????調整窗口大小
????訪問offsetWidth或是offsetHeight等破壞flush隊列的操作
flush隊列
為性能優化考慮,瀏覽器自身會維護一個flush隊列,該隊列存儲著回流的內容,每經過一段時間或該隊列達到一定長度后瀏覽器就會一次性將其全部回流完成,實現優化性能的目的。但當開發者訪問offsetwidth,offsetheight,width,height等屬性時,瀏覽器為了給開發者返回該元素準確的值會破壞flush隊列,致使瀏覽器自身優化失效
頁面優化性能方法
代碼層面
元素位置變換時盡量使用css3的transfrom來代替top left的操作,因為變換僅僅影響圖層的組合位置
????使用opacity來代替visibility,因為透明度并不觸發重繪
????????注:透明度改變時GPU在繪畫時只是簡單的降低之前畫好紋理的alpha值來達到效果
????將多次class樣式改變操作合并為一次(預先定義改變后的class)
????使用display:none將dom元素離線后修改
????利用文檔碎片documentFragment收集短時間內回流元素后一次回流添加到頁面(vue同款優化)
????動畫實現過程中使用transfrom:tranleteZ(0)使其提升為合成層通過GPU單獨渲染
????為動畫元素新建圖層并提高其z-index以減少隱式合成
????減少對flush隊列的訪問,盡量不要破壞瀏覽器自身優化
????單調色塊可使用合成層優化中的scale縮放來優化內存占用
????CSS在上JS在下,觸發瀏覽器的first paint且減少同步代碼阻塞渲染的機率
資源層面
????除首屏展示外其余資源(圖片、組件、視頻等)懶加載
????首屏中包含的視頻可以進行分割傳輸
????單調圖片過大導致性能問題時可使用canvas或是svg繪圖
????對HTML、JS、CSS資源進行壓縮,服務器開啟Gzip
????對靜態資源使用緩存
????使用CDN縮短用戶與資源的距離? ? *? 升級到HTTP2使資源可以享受二進制傳輸、首部壓縮、多路復用