理解关键的渲染路径
本文轉載自:《Understanding the Critical Rendering Path》,原文地址:https: //bitsofco.de/understanding-the-critical-rendering-path/
當瀏覽器從服務器接收到一個HTML頁面的請求時,到屏幕上渲染出來要經過很多個步驟。瀏覽器完成這一系列的運行,或者說渲染出來我們常常稱之為“關鍵渲染路徑”(Critical Rendering Path)。
理解CRP(Critical Rendering Path)相關的知識可以更好的提高網站的性能。那么理解我們從下面六個部分來理解CRP相關的知識:
- 列表內容
- 列表內容
- 構建DOM樹
- 樹建CSSOM樹
- 運行JavaScript
- 創建Render樹
- 生成布局
- 繪制(Painting)
構建DOM樹
DOM(文檔對象模型)樹是一個完全解析的HTML頁面對象。從<html>根元素開始到頁面中每個元素和文本的節點。元素嵌套在其他元素內則表示為子節點,每個節點包含完整的屬性元素。例如一個<a>元素,它就有與之相關的href節點。
來看下面這個簡單的DOM示例:
<html> <head> <title>Understanding the Critical Rendering Path</title><link rel="stylesheet" href="style.css"> </head> <body> <header><h1>Understanding the Critical Rendering Path</h1></header><main><h2>Introduction</h2><p>Lorem ipsum dolor sit amet</p></main><footer><small>Copyright 2017</small></footer> </body> </html>這將會創建一個像下面這樣的DOM樹:
HTML比較好的是它可以執行部分。完整的文檔不需要加載的內容會在頁面的開始呈現。然而,比如CSS和JavaScript可以阻止頁面的呈現。
構建CSSOM樹
CSSOM(CSS對象模型)是一個表示DOM樣式的對象。它類似于DOM,但是是每個節點相關的樣式,包括他們是否顯式聲明或隱式繼承。
比如,在style.css文件中對上面的DOM有這樣的一些樣式:
body { font-size: 18px; }header { color: plum; } h1 { font-size: 28px; }main { color: firebrick; } h2 { font-size: 20px; }footer { display: none; }這將會構建像下面這樣的一個CSSOM樹:
CSS被認為是“渲染阻塞資源”。這意味著渲染樹(見下文)的構建離不開延續一個資源的解析完成度。不像HTML,CSS不能只用部分,因為CSS是具有繼承層疊特性。文檔后面定義的樣式可以覆蓋前面定義的樣式。所以,如果我們開始使用CSS時,之前的樣式表會被認為已經全部解析完。這也意味著CSS必須充分解析才能繼續下一個階段。
如果只運用于當前設備,CSS文件只被認為阻塞。<link rel="stylesheet">標簽可以接受一個media屬性,可以用來指定樣式適用于何種媒體。例如,我們有一個樣式表,它的media屬性設置為orientation:landscape時,如果在portrait模式下查看頁面,那么這個樣式表不會被認為是一個阻塞資源。
CSS還會阻塞JavaScript。那是因為JavaScript文件必須要等CSSOM構建完才會執行。
運行JavaScript
JavaScript被認為是一個“解析器阻塞資源”。這意味著解析的HTML文檔本身就會被JavaScript阻塞。
當解析器讀到<script>標記,不管是內部的還是外部的,它停止獲取(如果是外部的)并運行它。這個為什么,如果我們有一個JavaScript文件,該文件引用文檔中的元素,那么它必須放在這個元素的后面。
為了避免JavaScript解析器造成阻塞,可以添加async屬性,異步加載它。
<script async src="script.js">創建Render樹
Render樹是DOM和CSSOM的組合。這個樹代表最終在頁面上呈現的東西。這意味著它只抓住了可見的內容,將不包括設置了hidden的元素和CSS設置了display:none的元素。
使用上面的DOM和CSSOM,構建的Render樹如下圖所示:
生成布局
布局根據CSS樣式設置的大小來決定頁面在窗口中的尺寸。視窗的大小是由<head>中viewport標記來決定,如果沒有提供這個標記,默認使用的視窗寬度是980px。
例如,常見的設置視窗的meta標簽,指定的大小對應設備寬度:
<meta name="viewport" content="width=device-width,initial-scale=1">如果用戶訪問頁面寬度是基于設備的寬度1000px。那一半的視窗就是500px,10vw就是100px。
繪制(Painting)
最后就是繪制(Painting)步驟,把頁面可見的內容轉化為像素在屏幕上顯示。
繪制需要多少時間這取決于DOM的大小以及應用的樣式。有一些樣式需要更多的執行時間。例如,一個復雜的漸變背景圖像比一個單一顏色背景繪制需要更多的時間。
把它們結合起來
我們可以在DevTools中看到關鍵渲染路徑的過程。在Chrome瀏覽器中,點擊Timeline選項。
拿文章前面的示例(這里添加了<script>標簽):
<html> <head> <title>Understanding the Critical Rendering Path</title><link rel="stylesheet" href="style.css"> </head> <body> <header><h1>Understanding the Critical Rendering Path</h1></header><main><h2>Introduction</h2><p>Lorem ipsum dolor sit amet</p></main><footer><small>Copyright 2017</small></footer><script src="main.js"></script> </body> </html>如果我們看頁面的加載日志,將看到如下這樣的數據:
- 發送請求:發送GET,請求index.html
- 解析HTML并發送請求:解析HTML并且構建DOM樹,發送GET請求,請求style.css和main.js
- 解析樣式:根據style.css創建CSSOM
- 腳本評估:main.js評估
- 布局:基于HTML中的視窗meta生成布局
- 繪制:繪制頁面
基于這些信息,我們可以決定如何優化關鍵渲染路徑。我也將在后續的文章中深入的介紹這方面的知識。
博客名稱:王樂平博客
博客地址:http://blog.lepingde.com
CSDN博客地址:http://blog.csdn.net/lecepin
總結
- 上一篇: 基于事件的 NIO 多线程服务器
- 下一篇: mysql alter操作