天天看點

浏覽器的渲染性能

使用者都 希望他們通路的web應用是可互動且運作流暢的。是以,作為web開發者,你也要在這方面多花點功夫。你所做的頁面,不但要能被快速加載,還要能流暢運作:頁面的滾動要快速響應手指的動作,動畫和互動效果更要如絲般順滑。

浏覽器的渲染性能

要想編寫高性能的web站點或應用,你需要充分了解浏覽器是如何處理html/javascript/css的,進而確定你寫的代碼(或引用的第三方代碼)是盡可能高效的。

當今大多數裝置的螢幕重新整理率都是 60次/秒 。是以,如果在頁面中有一個動畫或漸變效果,或者使用者正在滑動頁面,那麼浏覽器渲染動畫或頁面的每一幀的速率,也需要跟裝置螢幕的重新整理率保持一緻。

也就是說,浏覽器對每一幀畫面的渲染工作需要在16毫秒(1秒 / 60 = 16.66毫秒)之内完成。但實際上,在渲染某一幀畫面的同時,浏覽器還有一些額外的工作要做(比如渲染隊列的管理,渲染線程與其他線程之間的切換等等)。是以單純的渲染工作,一般需要控制在10毫秒之内完成,才能達到流暢的視覺效果。如果超過了這個時間限度,頁面的渲染就會出現卡頓效果,也就是常說的jank,它是很糟糕的使用者體驗。

在編寫web頁面時,你需要了解你所寫的頁面代碼是如何被轉換成螢幕上顯示的像素的。這個轉換過程可以歸納為這樣的一個流水線,包含五個關鍵步驟:

浏覽器的渲染性能

javascript。一般來說,我們會使用javascript來實作一些視覺變化的效果。比如用jquery的<code>animate</code>函數做一個動畫、對一個資料集進行排序、或者往頁面裡添加一些dom元素等。當然,除了javascript,還有其他一些常用方法也可以實作視覺變化效果,比如:css animations, transitions和web animation api。

計算樣式。這個過程是根據css選擇器,比如<code>.headline</code>或<code>.nav &gt; .nav_item</code>,對每個dom元素比對對應的css樣式。這一步結束之後,就确定了每個dom元素上該應用什麼css樣式規則。

布局。上一步确定了每個dom元素的樣式規則,這一步就是具體計算每個dom元素最終在螢幕上顯示的大小和位置。web頁面中元素的布局是相對的,是以一個元素的布局發生變化,會關聯地引發其他元素的布局發生變化。比如,<code>&lt;body&gt;</code>元素的寬度的變化會影響其子元素的寬度,其子元素寬度的變化也會繼續對其孫子元素産生影響。是以對于浏覽器來說,布局過程是經常發生的。

繪制。繪制,本質上就是填充像素的過程。包括繪制文字、顔色、圖像、邊框和陰影等,也就是一個dom元素所有的可視效果。一般來說,這個繪制過程是在多個層上完成的。

渲染層合并。由上一步可知,對頁面中dom元素的繪制是在多個層上進行的。在每個層上完成繪制過程之後,浏覽器會将所有層按照合理的順序合并成一個圖層,然後顯示在螢幕上。對于有位置重疊的元素的頁面,這個過程尤其重要,因為一旦圖層的合并順序出錯,将會導緻元素顯示異常。

上述過程的每一步中都有發生jank的可能,是以一定要弄清楚你的代碼将會運作在哪一步。

note: 你可能聽說過 “rasterize” 這個術語,它通常被用在繪制過程中。繪制過程本身包含兩步: :1)建立一系列draw調用;2)填充像素。 第二步的過程被稱作 “rasterization” 。是以當你在devtools中檢視頁面的paint記錄時,你可以認為它已經包含了 rasterization。(有些浏覽器會使用不同的線程來完成這兩步,不過這也不是web開發者能控制的了)

雖然在理論上,頁面的每一幀都是經過上述的流水線處理之後渲染出來的,但并不意味着頁面每一幀的渲染都需要經過上述五個步驟的處理。實際上,對視覺變化效果的一個幀的渲染,有這麼三種 常用的 流水線:

浏覽器的渲染性能

如果你修改一個dom元素的”layout”屬性,也就是改變了元素的樣式(比如寬度、高度或者位置等),那麼浏覽器會檢查哪些元素需要重新布局,然後對頁面激發一個reflow過程完成重新布局。被reflow的元素,接下來也會激發繪制過程,最後激發渲染層合并過程,生成最後的畫面。

浏覽器的渲染性能

如果你修改一個dom元素的“paint only”屬性,比如背景圖檔、文字顔色或陰影等,這些屬性不會影響頁面的布局,是以浏覽器會在完成樣式計算之後,跳過布局過程,隻做繪制和渲染層合并過程。

浏覽器的渲染性能

如果你修改一個非樣式且非繪制的css屬性,那麼浏覽器會在完成樣式計算之後,跳過布局和繪制的過程,直接做渲染層合并。

第三種方式在性能上是最理想的,對于動畫和滾動這種負荷很重的渲染,我們要争取使用第三種渲染流程。

note: 如果你想對哪些屬性會觸發css triggers和高性能動畫方面了解更多,請參考:使用渲染層合并屬性。

性能優化是一門做減法的藝術。我們首要要盡力簡化頁面渲染過程,然後要使渲染過程的每一步都盡量高效。在很多時候,我們需要跟浏覽器一起努力來建立高性能web應用,而不是跟浏覽器對着幹。要記住,以上列舉的流水線中的每一步,在時間消耗上是各不相同的,有些步驟是相對更費時的。

接下來,讓我們深入到這個流水線中的每一步去看看。我們會以一些常見問題為例,闡述如何發現和分析這些問題,并嘗試去解決它們。

浏覽器的渲染性能

想深入了解渲染性能嗎?快看看這堂課程吧 它能幫助你了解浏覽器是如何把html/css/javascript代碼轉換成螢幕上你看到的一個個像素的 如何使用devtools來測量頁面性能、以及如何優化你的頁面渲染速度。

繼續閱讀