h5渲染效能一瞥

IT大咖說發表於2018-08-23

h5渲染效能一瞥


內容來源:2018 年 6 月 30 日,餓了麼前端主管向勇在“餓了麼技術沙龍・第27彈 【前端專場】”進行《h5渲染效能一瞥》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:2488 | 7分鐘閱讀

獲取嘉賓演講視訊及PPT:suo.im/4SkvOx

摘要

前端效能按照型別來分主要分為載入效能和渲染效能。載入效能對於首屏的展示及其重要,而渲染效能對於頁面載入完成後的互動體驗極其重要。但目前絕大部分同學在提到前端效能的優化時都會預設等同於對載入效能的優化,而忽略了渲染效能。本次議題就從幾個比較常見的角度聊聊開發中會無意識碰到的渲染效能問題。

H5 VS Native

在將H5和native進行對比的時候,我們通常能想到的一點就是“快”,H5相對於native開發和上線都會快一些,一般的活動頁面和非關鍵頁面更多的傾向於H5來開發。

當然H5也有相應的缺點,它的載入和操作會慢一些,抽象來看就是效能問題。載入慢對應的是載入效能,操作慢對應的是渲染效能。載入效能可被定義為頁面首次載入時候的效能,這方面的優化方案主要有靜態資源壓縮、懶載入、雪碧圖、CDN、server push等。

渲染效能可被定義為頁面進行操作/互動時候的效能,對於這方面的優化可能並不太容易想到。我在面試的時候也經常會問面試者關於效能優化的問題,不過大部分提到的優化方案都是關於載入效能,少部分會提到GPU加速,相對來說這部分同學的CSS技能會高一些。

渲染

一般一次渲染都會經過JavaScript > style > layout > paint > compoasite這樣的過程。在做動畫的時候可以進行優化,將layout和paint省略掉,這其實是將做動畫的元素提升為一個單獨的層。

渲染效能的優化可以針對渲染過程中的每一步來做,下面列出了google開發者論壇中提到的具體優化措施

  • 優化JS執行(JS)

  • 縮小樣式計算的範圍並降低其複雜性(style)

  • 避免大型、複雜的佈局和佈局抖動(layout、paint)

  • 使用輸入處理程式去除抖動(layout、paint)

  • 堅持僅合成器的屬性和管理層技術(composite)

  • 簡化繪製的複製度、減小繪製區域(paint、composite)

層的優化

上面加粗的兩個優化手段可以總結為層的優化,也就是開啟GPU加速。這裡我們先假設一個場景,在一個頁面中存在兩個水平排列的元素1、2,他們分別位於左右兩端,我們要做的是將1移動到2的位置。對此最簡單的方案是設定position並改變right或left的值。第二種方式是使用transform:translateX,並加上 will-change: transform/transform: translate(0)將它提升為單獨的層,這種方案的好處在於啟用了GPU加速。

這樣看來只要應用GPU加速就能很好的解決動畫優化問題,但是實際應用中的頁面往往要比上面所描述的場景複雜的多。就拿餓了麼的H5頁面來說,它除了有輪播外還涉及到頁面滾動、點選展開,返回頂部等。當開啟layer borders檢視時會發現滑動的過程中如果輪播圖正在播放整個頁面就會建立很多不必要的層。另外開啟Paint flashing檢視重繪情況時也會發現每次輪播圖播放都會導致整個頁面重繪。這種問題在低端手機上可能會造成閃屏,需要額外注意。解決方案其實前面也提到過就是要將做動畫的元素提升為一個單獨的層(合成層)

之前說過動畫的問題有兩種解決方案,如果這兩個方案結合在一起又會怎麼樣呢,也就是將position和will-change寫在同一個元素上,這在實際寫程式碼的過程中是很容易碰到的。由此引出了新的問題,浮動元素(渲染層)和合成層的關係。對此我個人做了下總結:若合成層的z-index值小於下方兄弟元素,且他們有重疊,則下方兄弟元素也會被提升為合成層。

h5渲染效能一瞥

上圖是餓了麼頁面的簡化場景,區域1是可滑動動畫區,使用flex佈局實現,區域2是店鋪列表,區域3是店鋪資訊,這兩個區域都新增了position:relative。

這種實現方式沒有指定浮動層的z-index值,因此在區域1進行滑動的時候,下方的每個店鋪列表都會被提升為單獨的層。在為區域1設定position:relative和z-index:1(高於下層)之後下方的層就不會再被提升了(此時下層z-index未設定)。

層爆炸

h5渲染效能一瞥

注意圖中標記區域,當點選展開/收起活動的小三角的時候會有一個旋轉180度的互動效果,相信大家對此都很熟悉。這種效果實現起來也很簡單,設定transition過渡屬性就能完成。

在實際操作的時候檢視層級會發現,每個商店列表都被提升成單獨的層且有很多巢狀。造成此問題的原因和前面的案例類似,主要還是沒有給擁有過渡動畫效果的小三角元素新增z-index值,解決方案同樣是為動畫元素設定z-inde。

這一系列的問題涉及到一個概念:層壓縮,即如果多個渲染層同一個合成層重疊時候,這些渲染層會被壓縮到一個GraphicsLayer中。

另外如果元素有動畫/過渡效果,可未指定層級順序高於下方浮動層,此時會假定下方的浮動層在動畫期間會受影響,從而無法被壓縮。

減少繪製區域

一般我們編寫頁面的時候都會為頭部和底部設定固定浮動,這涉及到減少繪製區域的優化策略。在沒有設定浮動的情況下,每次頁面滾動頭部和底部就會被重新渲染,解決方案是設定浮動後將這些浮動的頭部和底部提升為單獨的層。


相關文章