兄dei,據說你動畫很卡?

導語: 幾個星期前,由於公司活動,須要作一個比較炫酷的H5動畫, 一頓猛如虎的coding以後,發現運行起來卡成狗,當時絕望的想要出家,還好組內有經驗比較豐富的動畫大神幫忙調整,順利度過難關。javascript

做爲一個有追求的程序員!!!痛定思痛!!!一樣的悲劇絕對不能在同一個技術面發生兩次!!!流着淚寫下該篇總結,但願能夠給你們一些啓發。

本文目錄:

爲何動畫會有卡頓感?

回答這個問題前,咱們應該要明白一個問題,爲何咱們會感到動畫在動web

  1. 動畫的實現原理,是利用了人眼的「視覺暫留」現象,在短期內連續播放數幅靜止的畫面,使肉眼因視覺殘象產生錯覺,而誤覺得畫面在「動」。

  1. 大多數設備的刷新頻率是 60 次/秒,(1000/60 = 16.6ms)也就說是瀏覽器對每一幀畫面的渲染工做要在 16ms 內完成,超出這個時間,頁面的渲染就會出現卡頓現象,影響用戶體驗。

綜上,咱們或以爲動畫卡,一個很大的緣由就是由於 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 提供的性能分析工具,以便咱們更好分析問題。

強大的chrome性能分析工具介紹

  • performance

使用 Performance 工具時,爲了規避其它 Chrome 插件對頁面的性能影響,咱們最好在無痕模式下打開頁面

點擊左上角實心圓開始錄製,看下性能分析面板。

重點介紹下圖中標紅處:

FPS:這是一個和動畫性能密切相關的指標,它表示每一秒的幀數。圖中綠色柱狀越高表示幀率越高,體驗就越流暢。若出現紅色塊,則表明長時間幀,極可能會出現卡頓。圖中以綠色爲主,偶爾出現紅塊,說明網頁性能並不糟糕,但仍有可優化的空間。

CPU:表示CPU的使用狀況,不一樣的顏色片斷表明着消耗CPU資源的不一樣事件類型。這部分的圖像和下文詳情面板中的Summary內容有對應關係,咱們能夠結合這二者挖掘性能瓶頸。

summary: 渲染過程當中,每一個部分的耗時佔比。

  • Layers

是否是已經被這個高逼格的界面深深震撼到了!!!

重點看下 Paint flashing, Layer borders, FPS meter:

  • Paint flashing: 標記當前正在重繪的元素,(元素會被一個綠色的半透明遮罩蒙上),如上圖;

  • Layer borders: 複合層

    1. 黃色邊框: 有動畫 3d 變換的元素,表示放到了一個新的複合層(composited layer)中渲染。
    2. 藍色的柵格:這些分塊能夠看做是比層更低一級的單位,這些區域就是 RenderLayer。
  • FPS meter: GPU性能監控

    1. Frame Rate: 幀率。
    2. GPU Raster:GPU 光柵(默認開啓)。
    3. GPU Memory: 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>
複製代碼

運行結果:

  • Layers

  • performance

性能分析:

  1. 圖中移動的小方塊在不停的重排重繪過程當中。

  2. GPU 的內存使用率爲2.4 ~ 4.9 之間。

  3. 一秒內重排和重繪的耗時分別爲7.3ms4.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>
複製代碼

運行結果:

  • Layers

  • performance

性能分析:

  1. 圖中移動的小方塊沒有發生重排和重繪,只有一個圖層合併。

  2. GPU 的內存使用率幾乎爲0。

  3. 一秒內重排和重繪的耗時分別爲0ms0ms,圖層合併時間爲89us

比較上述兩種寫法能夠得處: 開啓GPU加速時的動畫性能要比不開啓高效。

  • 未開啓GPU加速:
  • 開啓GPU加速:

寫到這裏,你們可能會有疑問,爲何開啓GPU加速就沒有發生重排和重繪 ?是否是全部動畫所有都開啓GPU加速,就會變的很快?

下面就來分析這兩個問題:

1. 爲何開啓GPU加速就沒有發生重排和重繪 ?

觀察上圖:

在開啓GPU加速時,運動的紅色方塊開啓了新的合成層,因此不用再重排重繪,只須要一個合成圖層的時間。

2. 是否是全部動畫所有都開啓GPU加速,就會變的很快?

由於開啓GPU加速後會創建新的圖層,新的圖層就須要必定的內存空間,並且圖層在合成時,圖層越多耗費的時間確定也是越多的,因此瘋狂的開啓GPU加速,不但不能解決性能問題,反而可能會帶來性能問題

以下 (GPU內存使用較高):

綜上所述: 合理的開啓GPU加速,創建新的合成層,能夠給性能帶來很大的提高。

那麼,都有那些放法創建新的合成層呢?

親測有效的方法:

  • 使用css屬性:

    1. transform: translate3d(0, 0, 0);
    2. will-change: '將會發生變化的屬性';
    複製代碼
  • 標籤:

    <video></video>
    <canvas></canvas>
    複製代碼

總結

經過此篇文章,咱們應該對動畫性能分析有一個比較系統的認識:

  1. 爲何會有卡頓感產生?
  2. 瀏覽器每一幀的渲染工做是怎麼進行的?
  3. 如何使用chrome開發工具對動畫性能進行分析?
  4. GPU加速和普通渲染的區別在哪裏?
  5. 咱們應該如何開啓GPU加速?

動畫卡頓問題的分析,不像是查找js上的bug,有邏輯可尋,因此在遇到問題時,咱們只有明白底層的原理,結合分析工具,才能更好的發現問題。

相關文章
相關標籤/搜索