避免無用的渲染繪製(Avoiding Unnecessary Paints)

池中物willian發表於2014-04-24

本文翻譯自html5rock上的文章,文章英文原版地址在最後給出。

文中的Paints我翻譯成渲染繪製,我自己是這麼理解。

開始


 

 

繪製(渲染)一個網站或者一個應用的元素對瀏覽器來說開銷是很大的,它會對執行時的效率產生負面影響,在這篇文章中我們將快速的過一遍,哪些情況會導致導致繪製事件在瀏覽器中產生,以及如何在你今後的工作中儘量避免沒必要的繪製。

 

繪製(渲染):一場超快的旅行

 


 

瀏覽器的主要任務之一就是將DOMCSS轉換成畫素並繪製到屏目上,這是一系列複雜的處理過程。瀏覽器先讀取HTML標籤並由此建立DOM樹,它對CSS也是進行了類似的工作,讀取CSS並建立CSSOM樹,然後將兩者合併,最終我們就可以根據合併後的結構渲染成畫素到屏目了

 

繪製過程本身就挺有趣。在Chrome瀏覽器中,合併後的DOM樹與CSS樹被一款名叫Skia的軟體進行柵格化。如果你曾使用過CANVASAPI,那麼你會覺得它們的API非常相似。

不光是moveTo, lineTo等這些API,另外的一些高階API也一樣非常相似。本質上來講,所有需要被繪製的元素都將被提取到能被Skia執行的集合中,執行後輸出的是一堆點陣圖。這些點陣圖將被上傳到GPU中,GPU將幫他們組合在一起並最終輸出到屏目上。

 

Skia的工作量是直接受你在元素上所應用的樣式引響的。如果你在元素應用的樣式演算法很複雜那麼,會大大加重Skia的工作。你可以參考這篇文章article on how CSS affects page render weight,以更深的理解CSS如何影響頁面渲染。

 

總而言之,繪製工作費時間,如果我們不減少繪製,那麼可能會掉偵。使用者可能會注意到掉幀,看起來會閃一下。這對於我們的APP上來說是從根本上傷害了使用者體驗。我們不希望看到這樣的結果吧,so讓我們來看看哪些東西會產生必要的繪製(渲染)工作,以及我們能對這些做些啥優化。

 

Scrolling(滾動)


 

無論你是往上還是往下滾動,內容在顯示到屏目上之前瀏覽器都需要進行重繪。如果一切順利的話,可能產生重繪的區域會是很小一塊,但是即使是很小一塊,那一小塊元素可能就是應用了複雜的CSS樣式。所以不會因為繪製的區域小而繪製的速度會快。

為了看清哪些區域被重繪了,你可以使用Chrome中自帶的除錯工具,點選右上角的設定按鈕,選中 “Show Paint Rectangles後,在你的頁面中做一些簡單的互動,你便會看到一些會閃動的矩形框,那就是重繪的區域了。

 

滾動的效能表現,是你網站成功的關鍵。使用者真的會關心你的站點或應用滾動的是不是順暢,他們可不會喜歡滾動的不流暢的網站。我們在滾動時保證輕量的繪製工作,因此而得到的一個好處就是使用者看不到閃動或掉幀這類事情了。

 

我之前已經寫過一篇文章是關於滾動效能的,如果你想了解更我,可以參考這篇文章 article on scrolling performance

Interactions(互動)


 

互動是另一個產生繪製工作的原因,如:hovers, click,touches drags無論使用者執行了其中的哪一樣操作都會引發繪製或重繪。讓我們以hover舉個栗子,當hover某個元素時,Chrome不得不重繪那個被hover影響的元素。如果滾動時有一個很大很複雜的重繪工作,那麼你將會看到繪製幀頻的下降。

 

大家都想要好的、流暢的互動動畫,這我們又得關心一下動畫樣式在變化時的花費時間及效能成本

An unfortunate combination(不幸的組合)


 

當我滾動的同時移動滑鼠時會發生什麼 ?在無意中是完全有可能觸發昂貴的重繪開銷的,這將導致我的幀頻率小於16.7ms(我們應該保持在每秒60幀的頻率)。我已經寫了一個demo來更直觀的表達我所說的情況created a demo 希望你在滾動的同時移動滑鼠能看到hover效果。但是讓我們看看Chrome除錯工具告訴了我們什麼


 
 

在上圖中你可以看到,當我在某一個塊元素上(blocks)上hover時除錯工具已捕獲了繪製工作。為了看效果,我在demo中瘋狂的加重了樣式效果(縮放,陰間等動畫效果)。這導致幀頻逼近或偶爾間超過了幀頻的臨界值。最後我想要的是減少不必要的繪製工作,尤其是在滾動時。

我們如何實現呢,實現其實很簡單,技巧是新增一個scroll回撥handler處理函式,在這個函式內禁止hover效果,同時設定一個計時器,用以恢復hover效果。這意謂著我們保證在滾動時禁止一些開銷昂貴的互動效果,並且在停止滾動足夠的時間後恢復那些效果

 

實際應用時注意!

改變此項會影響你應用程式使用者體驗,所以明智的對待它,延時恢復效果要在你和的團隊能接受的時間範圍內


 

這是對應的程式碼

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

如你所見,我們用了一個class來決定hover效果是否被允許使用,下面就是這個classcss表示式

 

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {}

 

這就是所有的內容了

Conclusion(結束語)


 

渲染的效能表現對於使用者是否喜歡你的應用至關重要,你需要的是儘量保證繪製工作量保持在16ms幀頻率以下,為了幫助實現這一目標,你得使調式工具一直貫穿於你的開發過程中,確保幀頻保持在正常範圍內,並隨時修復上升的幀頻。

 

被忽略的互動過程,特別是重試繪製元素,是渲染效能的殺手,正如你所見,我們可以用一些簡單的程式碼解決掉這些問題。

 

看一看你的站點和應用,能不能做一些渲染繪製上面的優化

 

 

 

 

 

 


 

 

 

本文翻譯自:

http://www.html5rocks.com/en/tutorials/speed/unnecessary-paints/

 

我英文水平有限,湊合著翻,全當自我學習歡迎交流學習

 

========================================================

 

轉載處請註明:部落格園(王二狗)willian12345@126.com

 

 

 

 

相關文章