頁面的更新


談渲染效能的時候,很多人會想到reflow和repaint,不過這次要來討論的是瀏覽器渲染畫面所要進行的lifecycle。
從lifecycle的top-down視角看reflow和repaint,個人認為會比較有感覺。

渲染過程

瀏覽器在渲染畫面的時候,會由搭配DOM與CSSOM渲染合成render Tree,可參考這個影片

渲染時間

大部分的裝置更新畫面頻率是60fps,如果畫面有執行animation, transition或是滾動畫面時,畫面會持續的更新。
60fps的更新頻率大概是16ms(1 second / 60 = 16.66ms)
所以你可以大膽的假設,只要畫面處理的程式縮減到10ms以下,就可以讓頁面使用起來很流暢。
反之如果程式執行時間超過17ms以上,會讓畫面的使用體驗變得卡卡的。

關於渲染


以下是Google developer網站提供的pipeline,主要顯示出五個步驟
這裡寫了關於渲染的流程,以下抓一些比較重要的整理出來分享

基本上分成:

  1. JS/CSS:透過JS或CSS執行Visual changes。
  2. Style:瀏覽器重新計算每個元素改變的style,分派個別的CSS到特定的元素選擇器,例如:.header,到這邊可以視為產生了render Tree。
  3. Layout:如果你改變element的地理位置,例如:width, height或position,將會重新檢查相關的元素的變化。
  4. Paint:負責介面的渲染,例如渲染text, colors, images, borders, shadows……。
  5. Compositing:組裝合成頁面的元素,頁面上可能會有很多圖層,因此決定圖層的先後順序會決定頁面如何呈現。

rasterize

這篇文章有提到一個名詞叫做rasterize,中文叫點陣化,也就是把painting組合起來。
為什麼要組合呢?因為渲染畫面會做以下兩件事情:

  1. 產生draw calls的list
  2. 填滿pixels

渲染方式

渲染大致分成上圖的五個步驟,但是事實上並不需要每次都執行這五個步驟,可分成三個部分看:

  1. 全部都執行 - JS / CSS > Style > Layout > Paint > Composite
    如果你改變了layout的property,如上面提到的,瀏覽器會重新檢查相關的元素的變化並且重新計算元素(reflow),任何影響到的區塊也會重新渲染(repaint),最後進行組合。


2. 不執行Layout - JS / CSS > Style > Paint > Composite
如果你只改變paint only的property,例如:image, color, shadows……,畫面將會不去重新計算相關的元素(元素的位置沒改變,沒有重新計算也很合理),但是會執行重新渲染的動作(repaint),最後進行組合,


3. 不執行Layout與Paint - JS / CSS > Style > Composite
如果你改變的property,不需要layout也不需要paint,瀏覽器就會直接跳到組合的部分。

看完有什麼感覺呢?嗯…感覺起來…很廢話?但是卻是很重要的觀念
如果在開發的時候,選擇適合的方式將會提升專案部分的效能體驗。
第三點是效能最好,也是很多追求高效能開發上所追求的lifecycle。

reflow與repaint

看完上面的lifecycle之後,相信應該對這兩者有大致的認識了。

  1. reflow - 重新排列/回流:相關屬性發生變化就會重新計算。
  2. repaint - 重新繪圖:可見的元素發生paint變化會進行重繪。

小結論:由上面的觀察可以得知,如果reflow發生,一定會進行repaint。

那我們要追求高效能嗎


客戶與產品企劃:當然要追求高效能呀!!
工程:是!也…不是
迷:whaz?

首先,如果能做出流暢的頁面體驗當然好,畢竟應該沒有人不希望自己的做出來的東西不好用吧?
但是任何事情都需要在一定的scale中做出取捨,讓我們來看Google Developers寫下的這段話:
Performance is the art of avoiding work, and making any work you do as efficient as possible. In many cases it’s about working with the browser, not against it. It’s worth bearing in mind that the work listed above in the pipeline differ in terms of computational cost; some tasks are more expensive than others!

我們從lifecycle可以更了解瀏覽器是如何運作網頁執行的,但是並不代表我們一定要去挑戰它


迷:什麼?工程師不就是要不斷挑戰自我嗎?怎麼會這麼想
再來highlight一次上面一段話:
It’s worth bearing in mind that the work listed above in the pipeline differ in terms of computational cost; some tasks are more expensive than others!

開發與效能

如果今天如果今天你做其他任務的產值比提升效能這個任務還高,那麼你會選擇花時間去優化嗎?
又或是為了提升效能,讓整個前端開發架構變得四不像難以維護,這是需要去做的嗎?
考量到這些隱藏成本之後,相信你心中就會有答案了。

小結

大致上了解這些觀念應該就能輔助一些日常開發上的習慣了,我個人不喜歡去花太多時間去記憶,因此建立在理解觀念的前提下,觀看文件才能有效提升效率。

參考資料

  1. https://developers.google.com/web/fundamentals/performance/rendering
  2. https://www.chromium.org/developers/design-documents/oop-iframes/oop-iframes-rendering

圖片來源

  1. Google Developers
  2. chromium.org