此文已由做者袁申受權網易雲社區發佈。
html
歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。html5
有數的數據大屏能夠在一塊屏幕上展現若干張不一樣的圖表,以炫酷的方式展現各類業務數據。其中有些圖表使用CSS實現了餅圖輪播、地圖標記點閃爍等動畫,然而在一張大屏上同時顯示了許多張圖表時,持續的動畫效果有時會出現掉幀、卡頓的狀況,須要對動畫性能進行優化。本文簡單介紹了chrome瀏覽器性能分析工具和CSS動畫使用GPU加速進行性能優化的解決方案。web
這是瀏覽器渲染引擎的處理過程:chrome
接收到文檔後,渲染引擎會對HTML文檔進行解析生成DOM樹、對CSS文件進行解析生成CSSOM樹;同時執行頁面中的JavaScript代碼;最終根據DOM樹和CSSOM樹,計算樣式(Caluclate Style)生成渲染樹,渲染樹中,只會包含即將顯示在頁面中的元素及其樣式信息(如head元素、display爲hidden的元素就不會包含在渲染樹中);根據渲染樹須要進行佈局(layout)來計算每一個元素在頁面上的位置;數據庫
接下來渲染引擎開始進行繪製(paint),這一步分爲若干階段:根據渲染樹將每層(layer)的各個元素繪製,而後將繪製出的若干連續圖像進行柵格化(Rasterization),最後將柵格化後的圖像合成(composite)爲要顯示在屏幕上的圖像。對每一層的繪製是由瀏覽器來完成的;最後的合成是由GPU來完成;而柵格化過程取決於瀏覽器的設置,chrome默認開啓GPU柵格化,不然由CPU進行。瀏覽器
當首次將DOM樹構建完成後,每次頁面發生改變時進行進行的主要流程爲:
緩存
其中CSS動畫不會調用JavaScript,咱們知道,在渲染中主要消耗時間的是Layout/Reflow和Paint/Repaint的過程,所以要儘可能避免和減小這兩個階段的時間。安全
這是一個CSS動畫,控制一個方塊的top、left屬性實現平移。使用Chrome提供的瀏覽器性能分析工具分析動畫的性能,打開瀏覽器開發者工具後,在標籤中選擇performance打開性能分析面板。在性能分析面板中對當前頁面進行錄製,錄製結束後分析結果中能夠查看頁面在這段時間內的FPS、CPU佔用等狀況,在main中包含了瀏覽器的渲染流程,包括Scripting、Rendering、Painting等。性能優化
執行這個CSS動畫時,不涉及JavaScript的調用;紫色部分是render,依次分別爲Recaculate Style、Layout和Update Layer Tree;綠色部分爲Painting,依次分別爲Paint和Composite Layers。bash
在下面的面板中也能夠查看當前時間段內各個階段執行時間
more tools中的rendering也包含若干查看渲染有關的選項:
勾選paint flashing,頁面上會以綠色方塊顯示須要重繪的區域,當前小方塊進行了平移,所以須要重繪;勾選layer borders,會以黃色方框顯示頁面的分層狀況,此時頁面只有一個層,藍色的線顯示了tile的劃分,它是一個layer中的分塊;FPS meter能夠顯示頁面的FPS、是否使用GPU進行柵格化過程和GPU顯存使用狀況,因爲默認開啓了GPU柵格化,GPU Raster顯示爲on:
more tools中的layers能夠查看頁面分層,以及每層的詳細信息等:
經過對這些數據咱們能夠對頁面加載的性能瓶頸進行分析和針對性的優化。
瀏覽器的GPU加速功能是將須要進行動畫的元素提高到一個獨立的層(layer),這樣就能夠避免瀏覽器進行從新佈局(Reflow)和繪製(Repaint),將原先的瀏覽器使用CPU繪製位圖來實現的動畫效果轉爲讓GPU使用圖層合成(composite)來實現,若是兩張圖層內部沒有發生改變,瀏覽器就再也不進行佈局和繪製,直接使用GPU的緩存來繪製每一個圖層,GPU只負責將各個圖層合成來實現動畫,這就能夠充分利用GPU的資源和優點,減輕CPU的負載,可使動畫更流暢。經過改變兩張圖片之間的相對位置代替繪製一張圖片的每一幀來實現動畫,雖然視覺效果相同,但省去了許多繪製的時間。
爲了讓瀏覽器將動畫元素提高到一個獨立的層,可使用transform和opacity屬性來實現動畫,當設置了這兩個屬性之一時,瀏覽器會自動進行這一優化操做(透明度的變化能夠經過GPU改變a通道來實現,不須要瀏覽器進行重繪)。對於上面的動畫,能夠改變transform來代替改變left和top屬性:
對這個動畫進行分析,能夠看到使用transform後瀏覽器爲小方塊單獨設置了一個層,而且再也不觸發瀏覽器更新樣式:
若是動畫並不須要對transform和opacity屬性作出改變,可使用其餘的方法強制瀏覽器爲這些元素建立單獨的層,好比設置一個沒有效果的樣式:transform:translateZ(0);這不會對元素的實際樣式作出改變。但這是一種hack,規範的作法是使用will-change屬性,設置它的值爲須要作變換的屬性,如will-change: left;瀏覽器就會知道left這個屬性會發生變化,所以會開啓硬件加速優化性能。
這是使用will-change屬性的平移動畫,一樣也爲小方塊設置了單獨的圖層。
既然設置了will-change屬性能夠開啓GPU加速,那麼:
* { will-change: all;}複製代碼
看起來好像是一勞永逸的方法,但其實這反而會下降頁面的性能,雖然硬件加速能夠提升GPU的使用,但從layers中的信息能夠看出,每一個層都須要消耗必定的內存,過多的內存佔用也會形成性能的降低;過多的層傳輸到GPU的過程也會消耗必定的時間,此外也形成合成階段的時間佔用較長,所以並非獨立的層越多越好。最好的作法是對那些可能動畫的元素設置屬性,並在動畫結束後就移除這個屬性。
根據以上的分析,總結GPU實現動畫的優缺點:
優勢:
利用了GPU合成圖層實現動畫,能夠作到動畫平滑、流暢
動畫合成工做在GPU線程,不會被CPU的js運行阻塞
缺點:
繪圖層必須傳輸到GPU,當圖層較多時傳輸過程可能會致使渲染緩慢
每一個複合層都須要消耗額外的內存,過多的內存可能致使瀏覽器的崩潰
複合層合成須要更多的時間
對於通常的HTML的元素,遵循上述的方法就能夠了,但有數大屏中的圖表是使用SVG元素來繪製的,因爲並非標準的DOM元素,Chrome並不能支持SVG元素的硬件加速,即便設置了transform、will-change等屬性,單個的SVG元素也不能做爲單獨的層進行繪製。
從這個使用transform實現的SVG動畫能夠看到即便使用了transform,動畫部分的頁面仍然須要重繪。
對於下面這個有多個圖表的頁面,其中只有一個圖表有動畫,在動畫過程當中,若是隻有一個圖層,那麼須要將整個圖層進行重繪,雖然如今Chrome已經能夠智能選擇最小的重繪區域進行增量繪製,但當圖層較大時這樣的判斷也會形成必定的開銷。所以能夠考慮將有動畫的圖標單獨放在一個圖層中,其餘沒有動畫的圖表和頁面是的其餘元素仍然和背景在一個圖層中:
分別對分層的和未分層的頁面進行5次性能測試,將分析結果進行對比:
能夠看出,分層後每幀動畫繪製的總時間有明顯降低,主要體如今繪製(painting)過程當中:其中paint時間的減小應該是由於每次重繪的圖層面積只有圖表區域,所以須要更少的時間來判斷須要更新紋理的區域;composite layers時間的減小,應該主要是因爲須要繪製的圖層的減少,致使紋理上傳GPU和調用OpenGL繪製接口的時間減小了;而rendering時間的增長緣由還須要進一步的調研。
在實際使用中,能夠在某張圖表須要動畫時,設置SVG標籤的will-change屬性,將SVG元素提高到獨立的層,來減小動畫繪製時間;而圖表沒有動畫時則不須要特別處理,避免過分繪製形成的內存佔用增長和圖層傳輸、合成時間的增長。
更多網易技術、產品、運營經驗分享請點擊。
相關文章:
【推薦】 關於數據庫查詢業務的幾點思考