頁面性能優化的利器 — Timeline


歡迎大家關注騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~

陳澤欽,騰訊移動客戶端工程師,目前就職於騰訊MIG移動互聯網事業群,負責騰訊瀏覽服務TBS的X5內核業務。

1. 網頁渲染的基礎

在前面整理的Chrome官方的渲染性能優化文章中,講述到了網頁生成過程中,主要包含如下幾個步驟:

* JavaScript。一般來說,我們會使用JavaScript來實現一些視覺變化的效果。比如用jQuery的animate函數做一個動畫、對一個數據集進行排序、或者往頁面里添加一些DOM元素等。當然,除了JavaScript,還有其他一些常用方法也可以實現視覺變化效果,比如:CSS Animations, Transitions和Web Animation API。

* 計算樣式。這個過程是根據CSS選擇器,比如.headline.nav > .nav_item,對每個DOM元素匹配對應的CSS樣式。這一步結束之后,就確定了每個DOM元素上該應用什么CSS樣式規則。

* 布局。上一步確定了每個DOM元素的樣式規則,這一步就是具體計算每個DOM元素最終在屏幕上顯示的大小和位置。web頁面中元素的布局是相對的,因此一個元素的布局發生變化,會聯動地引發其他元素的布局發生變化。比如,元素的寬度的變化會影響其子元素的寬度,其子元素寬度的變化也會繼續對其孫子元素產生影響。因此對於瀏覽器來說,布局過程是經常發生的。

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

* 渲染層合並。由上一步可知,對頁面中DOM元素的繪制是在多個層上進行的。在每個層上完成繪制過程之后,瀏覽器會將所有層按照合理的順序合並成一個圖層,然后顯示在屏幕上。對於有位置重疊的元素的頁面,這個過程尤其重要,因為一旦圖層的合並順序出錯,將會導致元素顯示異常。

參考tikizheng在Timeline的入門篇中所整理的框圖,更清晰地展示了頁面生成的流程。

網頁中的重繪過程是影響整體性能下降的關鍵點之一,因而網站開發者應該更多地去避免在站點中進行不必要以及不適時的重繪步驟,借助Inspector中的Timeline面板可以很好地剖析這一些存在的問題。

2. 實例講解

在此,本文將通過一個簡單的網頁Demo來講述Timeline的常用技巧

Demo頁面,具體如下:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>X5 CORE</title>
    <style type="text/css">
        body { font-size: 16px }
        p { font-weight: bold }
        span { color: red }
        p span { display: none }
        img { width: 100%; max-width: 300px }
    </style>

    <script>
      function a_click() {
        var span = document.getElementsByTagName('span')[0];
        span.textContent = 'Web performance'; // change DOM text content, lead to relayout
        span.style.color = 'green';  // change CSSOM property
      }
    </script>
  </head>

  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="X5.jpg" onclick="a_click()"></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline';  // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var div = document.createElement('div');
      div.textContent = '*** Add new element to DOM ***';
      div.style.color = 'blue';
      document.body.appendChild(div);
    </script>
  </body>
</html>

這是一個很簡單的網頁,展示了一行文字和圖片,而在body中有一段script對個別元素進行樣式和內容的調整;此外還有一個點擊事件,即點擊圖片后,會再次執行一段修改元素內容和樣式的腳本。

2.1 操作流程:

  • Ctrl+E 開始錄制

  • 刷新頁面

  • 點擊圖片,執行onclick事件

  • Ctrl+E 結束錄制

操作完畢后,Inspector在Timeline中記錄了這一過程中,與頁面相關的各項信息。

可以看到下圖中上方的兩個紅色框位置,該區域是Timeline面板的整體預覽區,分了三部分(FPS、CPU、NET)來展示,具體可查看Timeline使用詳情。首個紅色框位置,記錄了首次加載頁面時,所經歷的Loading -> Scripting -> Rendering -> Painting流程。而右邊的紅色框區域中,可見CPU中首先顯示了黃色(代表Scripting)的峰形區域,隨后顯示了紫色(代表Rendering)的峰形區域,表示了頁面在響應點擊事件后所進行的流程。

2.2 事件詳解:

通過滾輪在Flame框圖中,可以對頁面中的事件進行縮放,可已清晰地觀察到在首次加載過程中,所經歷的Loading -> Script -> Layout -> Paint -> Composite Layers等流程。

並且,在點擊了各個事件之后,下方的Summary中會羅列出更加具體的信息。比如,點擊Evaluate Script事件后,可以查看總共的耗時,並且可以鏈接到具體的JS源代碼:

而在網頁加載完畢后,對圖片進行了點擊操作,觸發了<img />標簽的onclick事件,開發者能夠在Flame框圖中查看到點擊事件中各個流程,其展現了所有的JS調用棧:

系統Event(click) ==> <img />綁定的onclick事件(html中第24行) ==> function a_click() (html中第14行)

2.3 綜合分析

由此可見,當在頁面已經得到生成了之后,利用JS去更改個別元素的內容(DOM結構變化),或者是調整元素屬性(CSSOM屬性變化),都會引起頁面重新進行Rendering -> Painting流程。如果這些是不必要的操作,則必定會導致網頁性能降低。

因此,對於開發者來說,應該要知道如何去定位網頁中發生重繪的區域。

3. 定位網頁中發生重繪的區域

開啟方式:在控制欄的右上角屬性按鈕中,選擇More tools — Rendering settings,然后在彈出的面板中選擇 Paint Flashing。

如下圖中的操作,在勾選了Paint Flashing后,還是在Demo頁面中,點擊圖片觸發JS事件,進而會span標簽的內容以及顏色,而在頁面預覽區域中,可以觀察到該行文本在刷新內容過程中,有綠色的方框進行高亮包圍,說明了這一部分區域發生了重新繪制。

另外一個重要的現象是,雖然點擊后的JS事件僅修改了<span>的內容,但是重繪卻發生在整一個<p>標簽中,說明了個別元素的重新繪制,一般會影響到父元素或者是周圍的元素,造成區域性重繪,因此在頁面中避免不必要的重繪顯得至關重要。

小技巧: 當發現頁面中,如果存在一些不必要的重繪現象,而又不能夠定位到具體的原因,可以對該區域中的各個元素,依次進行隱藏(在Element面板中設置visibility:hidden),觀察效果來定位。

4. 顯示composited layer的邊界

More tools — Rendering settings中,還可以開啟 Layer Borders,觀察頁面中的各個區域繪制情況。通過這一項功能,開發者能夠發現頁面中發生動畫或者是CSS transforms/transitions等發生了形狀或位置變化的元素,進而優化其渲染時間

Demo頁面比較簡單所以效果不明顯,利用官方圖片來展示Layer Borders的效果:

5. 在Paint Profiler中查看繪制細節

當在Flame框圖中點擊了 一個Paint事件,則會在詳情面板中出現一個Paint專有標簽:Paint Profiler

通過Paint Profiler面板,開發者可以知道該次Paint事件的繪制時間、繪制位置和大小等信息,並且能夠具體到某一個元素的繪制耗時:當拖動標尺,直至內容框中僅有目標元素Image的繪制時,即可觀察到其耗時(0.14ms/0.2ms),以及圖片區域的大小、位置等等信息。

相關推薦

讓頁面滑動流暢得飛起的新特性:Passive Event Listeners
Node直出理論與實踐總結
JavaScriptCore全面解析 (上篇)


 

此文已由作者授權騰訊雲技術社區發布,轉載請注明文章出處
原文鏈接:https://www.qcloud.com/community/article/169028001491011736
獲取更多騰訊海量技術實踐干貨,歡迎大家前往騰訊雲技術社區


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM