導語: 幾個星期前,由於公司活動,須要作一個比較炫酷的
H5
動畫, 一頓猛如虎的coding
以後,發現運行起來卡成狗,當時絕望的想要出家,還好組內有經驗比較豐富的動畫大神幫忙調整,順利度過難關。javascript
爲何動畫會有卡頓感?css
瀏覽器渲染繪製過程html
動畫性能分析實戰react
總結程序員
回答這個問題前,咱們應該要明白一個問題,爲何咱們會感到動畫在動?web
綜上,咱們或以爲動畫卡,一個很大的緣由就是由於 FPS
(幀率) 太低致使,也就是說每一幀的畫面不能的保證在16ms以內完成渲染工做,因此咱們會以爲卡頓。chrome
解釋清楚了會感到卡頓的緣由,你們是否是很好奇每一幀的渲染過程到底發生了什麼會致使它的渲染時間超過 16ms ? canvas
如今進入到咱們的第二部分,瀏覽器渲染繪製過程瀏覽器
Webkit
的渲染流程爲例分析下瀏覽器:處理HTML標記數據並生成DOM樹。
處理CSS標記數據並生成CSSOM樹。
將DOM樹與CSSOM樹合併在一塊兒生成渲染樹。
Layout(佈局):計算每一個 DOM 元素在最終屏幕上顯示的大小和位置。因爲 web 頁面的元素佈局是相對的,因此其中任意一個元素的位置發生變化,都會聯動的引發其餘元素髮生變化,這個過程叫 reflow
(迴流 or 重排)。
Paint(繪製):在多個層上繪製 DOM 元素的的文字、顏色、圖像、邊框和陰影等。
composite(渲染層合併):按照合理的順序合併圖層而後顯示到屏幕上。
每一幀的渲染通過如上步驟,呈如今用戶的眼前,當這些步驟時間的總和 > 16ms, 用戶就會有卡頓感產生。
在 動畫性能分析 部分,會重點結合Layout
, Paint
, composite
部分來具體分析動畫卡頓的緣由及優化方式,在此以前,咱們先了解下強大的 chrome
提供的性能分析工具,以便咱們更好分析問題。
使用 Performance 工具時,爲了規避其它 Chrome 插件對頁面的性能影響,咱們最好在無痕模式下打開頁面
點擊左上角實心圓開始錄製,看下性能分析面板。
重點介紹下圖中標紅處:
FPS:這是一個和動畫性能密切相關的指標,它表示每一秒的幀數。圖中綠色柱狀越高表示幀率越高,體驗就越流暢。若出現紅色塊,則表明長時間幀,極可能會出現卡頓。圖中以綠色爲主,偶爾出現紅塊,說明網頁性能並不糟糕,但仍有可優化的空間。
CPU:表示CPU的使用狀況,不一樣的顏色片斷表明着消耗CPU資源的不一樣事件類型。這部分的圖像和下文詳情面板中的Summary內容有對應關係,咱們能夠結合這二者挖掘性能瓶頸。
summary: 渲染過程當中,每一個部分的耗時佔比。
Paint flashing
, Layer borders
, FPS meter
:Paint flashing: 標記當前正在重繪的元素,(元素會被一個綠色的半透明遮罩蒙上),如上圖;
Layer borders: 複合層
FPS meter: GPU性能監控
綜上就是對
chrome
一些性能分析工具的簡單介紹,說了這麼多!!!讓咱們寫一些動畫實操一下吧!!!
下面就進入咱們最最重要的部分!!!動畫性能分析實戰
在瀏覽器中打開以下代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style> .react {position: absolute;width: 100px;height: 100px;background: #f00;animation: react-run 3s linear 0s infinite;} @keyframes react-run { 0% { top: 0px;left: 0px;} 25% {top: 0px;left: 200px;} 50% {top: 200px;left: 200px;} 75% {top: 200px;left: 0px;} 100% {top: 0px;left: 0px;} } </style>
</head>
<body>
<div class="react"></div>
</body>
</html>
複製代碼
運行結果:
性能分析:
圖中移動的小方塊在不停的重排重繪過程當中。
GPU 的內存使用率爲2.4 ~ 4.9 之間。
一秒內重排和重繪的耗時分別爲7.3ms
和4.9ms
。
這裏還有個值得注意的點:
2.4
變爲4.9
。以下圖:
圖層被光柵化後,分塊存入GPU
的內存中,當元素跨光柵移動時,兩塊內存都在變化,因此消耗天然加倍啦!!!
好,如今讓咱們開啓傳說中的 3D
引擎加速!!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.react {position: absolute;
width: 100px;
height: 100px;
background: #f00;
animation: react-run 3s linear 0s infinite;
transform: translate3d(0, 0, 0);
}
@keyframes react-run {
0% {transform: translate3d(0, 0, 0);}
25% {transform: translate3d(200, 0, 0);}
50% {transform: translate3d(200, 200, 0);}
75% {transform: translate3d(0, 200, 0);}
100% {transform: translate3d(0, 0, 0);}
}
</style>
</head>
<body>
<div class="react"></div>
</body>
</html>
複製代碼
運行結果:
性能分析:
圖中移動的小方塊沒有發生重排和重繪,只有一個圖層合併。
GPU 的內存使用率幾乎爲0。
一秒內重排和重繪的耗時分別爲0ms
和0ms
,圖層合併時間爲89us
。
比較上述兩種寫法能夠得處: 開啓
GPU
加速時的動畫性能要比不開啓高效。
GPU
加速:GPU
加速:寫到這裏,你們可能會有疑問,爲何開啓GPU
加速就沒有發生重排和重繪 ?是否是全部動畫所有都開啓GPU
加速,就會變的很快?
下面就來分析這兩個問題:
GPU
加速就沒有發生重排和重繪 ?觀察上圖:
在開啓GPU
加速時,運動的紅色方塊開啓了新的合成層,因此不用再重排
和重繪
,只須要一個合成圖層的時間。
GPU
加速,就會變的很快?由於開啓GPU
加速後會創建新的圖層,新的圖層就須要必定的內存空間,並且圖層在合成時,圖層越多耗費的時間確定也是越多的,因此瘋狂的開啓GPU
加速,不但不能解決性能問題,反而可能會帶來性能問題。
以下 (GPU
內存使用較高):
綜上所述: 合理的開啓
GPU
加速,創建新的合成層,能夠給性能帶來很大的提高。
使用css
屬性:
1. transform: translate3d(0, 0, 0);
2. will-change: '將會發生變化的屬性';
複製代碼
標籤:
<video></video>
<canvas></canvas>
複製代碼
chrome
開發工具對動畫性能進行分析?GPU
加速和普通渲染的區別在哪裏?GPU
加速?動畫卡頓問題的分析,不像是查找
js
上的bug
,有邏輯可尋,因此在遇到問題時,咱們只有明白底層的原理,結合分析工具,才能更好的發現問題。