頁面渲染機制

簡單渲染過程

url解析:html

  1. 用戶輸入URL地址web

  2. 瀏覽器解析URL解析出主機名後端

  3. 瀏覽器將主機名轉換成服務器ip地址(瀏覽器先查找本地DNS緩存列表 沒有的話 再向瀏覽器默認的DNS服務器發送查詢請求 同時緩存)瀏覽器

  4. 瀏覽器將端口號從URL中解析出來緩存

  5. 瀏覽器創建一條與目標Web服務器的TCP鏈接(三次握手)bash

  6. 瀏覽器向服務器發送一條HTTP請求報文服務器

  7. 服務器向瀏覽器返回一條HTTP響應報文app

  8. 關閉鏈接 瀏覽器解析文檔框架

  9. 若是文檔中有資源 重複6 7 8 動做 直至資源所有加載完畢dom

html解析:

  1. 將HTML構建成一個DOM樹(DOM = Document Object Model 文檔對象模型),DOM 樹的構建過程是一個深度遍歷過程:當前節點的全部子節點都構建好後纔會去構建當前節點的下一個兄弟節點。
  2. 將CSS解析成CSS去構造CSS Rule Tree
  3. 根據DOM樹和CSSOM來構造 Rendering Tree(渲染樹)。注意:Rendering Tree 渲染樹並不等同於 DOM 樹,由於一些像 Header 或 display:none 的東西就不必放在渲染樹中了。
  4. 有了Render Tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關係。
  5. 下一步操做稱之爲Layout,顧名思義就是計算出每一個節點在屏幕中的位置 layout render tree。
  6. 再下一步就是繪製(Paint),即遍歷render樹,並使用瀏覽器UI後端層繪製每一個節點。

Render Tree

渲染樹,表明一個文檔的視覺展現,瀏覽器經過它將文檔內容繪製在瀏覽器窗口,展現給用戶,它由按順序展現在屏幕上的一系列矩形對象組成,這些矩形對象都帶有字體,顏色和尺寸,位置等視覺樣式屬性。對於這些矩對象,FireFox稱之爲框架(frame),Webkit瀏覽器稱之爲渲染對象(render object, renderer),後文統稱爲渲染對象。

每個渲染對象都表明着其對應DOM節點的CSS盒子,該盒子包含了尺寸,位置等幾何信息,同時它指向一個樣式對象包含其餘視覺樣式信息。

每個渲染對象都對應着DOM節點,可是非視覺(隱藏,不佔位)DOM元素不會插入渲染樹,如<head>元素或聲明display: none;的元素,渲染對象與DOM節點不是簡單的一對一的關係,一個DOM能夠對應一個渲染對象,但一個DOM元素也可能對應多個渲染對象,由於有不少元素不止包含一個CSS盒子,如當文本被折行時,會產生多個行盒,這些行會生成多個渲染對象;又如行內元素同時包含塊元素和行內元素,則會建立一個匿名塊級盒包含內部行內元素,此時一個DOM對應多個矩形對象(渲染對象)。

Layout

建立渲染樹後,下一步就是佈局(Layout),或者叫回流(reflow,relayout),這個過程就是經過渲染樹中渲染對象的信息,計算出每個渲染對象的位置和尺寸,將其安置在瀏覽器窗口的正確位置,而有些時候咱們會在文檔佈局完成後對DOM進行修改,這時候可能須要從新進行佈局,也可稱其爲迴流,本質上仍是一個佈局的過程,每個渲染對象都有一個佈局或者回流方法,實現其佈局或迴流。

Paint

最後是繪製(paint)階段或重繪(repaint)階段,瀏覽器UI組件將遍歷渲染樹並調用渲染對象的繪製(paint)方法,將內容展示在屏幕上,也有可能在以後對DOM進行修改,須要從新繪製渲染對象,也就是重繪,繪製和重繪的關係能夠參考佈局和迴流的關係。

Reflow (迴流/重排)

當它發現了某個部分發生了變化影響了佈局,渲染樹須要從新計算。

緣由:

  1. DOM操做,如增長,刪除,修改或移動;
  2. 變動內容;
  3. 激活僞類;
  4. 訪問或改變某些CSS屬性(包括修改樣式表或元素類名或使用JavaScript操做等方式);
  5. 瀏覽器窗口變化(滾動或尺寸變化)

如何減小reflow

  1. 儘量限制reflow的影響範圍。須要改變元素的樣式,不要經過父級元素影響子元素。最好直接加在子元素上。
  2. 經過設置style屬性改變結點樣式的話,每設置一次都會致使一次reflow。因此最好經過設置class的方式。
  3. 減小沒必要要的DOM層級(DOM depth)。改變DOM樹中的一級會致使全部層級的改變,上至根部,下至被改變節點的子節點。這致使大量時間耗費在執行reflow上面。
  4. 避免沒必要要的複雜的CSS選擇器,尤爲是後代選擇器(descendant selectors),由於爲了匹配選擇器將耗費更多的CPU。

Repaint(重繪)

改變了某個元素的背景顏色,文字顏色等,不影響元素周圍或內部佈局的屬性,將只會引發瀏覽器的repaint,根據元素的新屬性從新繪製,使元素呈現新的外觀。重繪不會帶來從新佈局,並不必定伴隨重排; Reflow要比Repaint更花費時間,也就更影響性能。因此在寫代碼的時候,要儘可能避免過多的Reflow。

script解析

或許是因爲一般會在JavaScript腳本中改變文檔DOM結構,因而瀏覽器以同步方式解析,加載和執行腳本,瀏覽器在解析文檔時,當解析到<script>標籤時,會解析其中的腳本(對於外鏈的JavaScript文件,須要先加載該文件內容,再進行解析),而後當即執行,這整個過程都會阻塞文檔解析,直到腳本執行完纔會繼續解析文檔。就是說因爲腳本是同步加載和執行的,它會阻塞文檔解析,這也解釋了爲何如今一般建議將<script>標籤放在</body>標籤前面,而不是放在<head>標籤裏。如今HTML5提供defer和async兩個屬性支持延遲和異步加載JavaScript文件

defer和async

固然咱們能夠經過設置deferasync屬性來異步加載不過重要的腳本

這兩個屬性都告訴瀏覽器,他可能會在後臺加載腳本時繼續解析HTML,而後再在加載後執行腳本,這樣腳本下載不會阻止DOM構建和頁面呈現。用戶能夠在全部腳本完成加載以前看到頁面

二者的區別就是他們將在那一刻執行腳本,在這以前咱們須要瞭解瀏覽器爲其加載的每一個網頁追蹤細粒度時間戳

img

  • domLoading: 瀏覽器即將開始解析第一批收到的HTML文檔字節
  • domInteractive: 表示瀏覽器完成對全部HTML的解析而且DOM構建完成的時間點
  • domContentLoaded: 表示DOM準備就緒而且沒有樣式表阻止JavaScript執行的時間點
  • domComplete: 全部處理完成,而且網頁上的全部資源都已經下載完畢
  • loadEvent: 做爲每一個網頁加載的最後一步,瀏覽器會觸發onload事件,以便觸發額外的應用邏輯

defer的執行將在domInteractive完成以後,domContentLoaded以前開始,他保證腳本將按照他們在HTML中出現的順序執行,而且不會阻塞解析器

img

async腳本在完成下載以後和窗口load事件以前的某一個時間點執行,這意味着異步腳本可能不按他們在HTML中出現的順序執行,這意味着他們可能會阻止DOM構建

img

defer

<script src="app1.js" defer></script>
<script src="app2.js" defer></script>
<script src="app3.js" defer></script>
複製代碼

defer 屬性表示延遲執行引入的 JavaScript,即這段 JavaScript 加載時 HTML 並未中止解析,這兩個過程是並行的。整個 document 解析完畢且 defer-script 也加載完成以後(這兩件事情的順序無關),會執行全部由 defer-script 加載的 JavaScript 代碼,而後觸發 DOMContentLoaded 事件。

defer 不會改變 script 中代碼的執行順序,示例代碼會按照 一、二、3 的順序執行。因此,defer 與相比普通 script,有兩點區別:載入 JavaScript 文件時不阻塞 HTML 的解析,執行階段被放到 HTML 標籤解析完成以後。

async

<script src="app.js" async></script>
<script src="ad.js" async></script>
<script src="statistics.js" async></script>
複製代碼

async 屬性表示異步執行引入的 JavaScript,與 defer 的區別在於,若是已經加載好,就會開始執行——不管此刻是 HTML 解析階段仍是 DOMContentLoaded 觸發以後。須要注意的是,這種方式加載的 JavaScript 依然會阻塞 load 事件。換句話說,async-script 可能在 DOMContentLoaded 觸發以前或以後執行,但必定在 load 觸發以前執行。

從上一段也能推出,多個 async-script 的執行順序是不肯定的。值得注意的是,向 document 動態添加 script 標籤時,async 屬性默認是 true

CSS和JS阻塞規則

  1. CSS 不會阻塞 DOM 的解析,但會阻塞 DOM 渲染。
  2. JS 阻塞 DOM 解析,但瀏覽器會"偷看"DOM,預先下載相關資源。
  3. 瀏覽器遇到 <script>且沒有defer或async屬性的 標籤時,會觸發頁面渲染,於是若是前面CSS資源還沒有加載完畢時,瀏覽器會等待它加載完畢在執行腳本。

渲染優化

  1. HTML文檔結構層次儘可能少,最好不深於六層;
  2. 腳本儘可能後放,放在前便可;
  3. 少許首屏樣式內聯放在標籤內;
  4. 樣式結構層次儘可能簡單;
  5. 在腳本中儘可能減小DOM操做,儘可能緩存訪問DOM的樣式信息,避免過分觸發迴流;
  6. 減小經過JavaScript代碼修改元素樣式,儘可能使用修改class名方式操做樣式或動畫;
  7. 動畫儘可能使用在絕對定位或固定定位的元素上;
  8. 隱藏在屏幕外,或在頁面滾動時,儘可能中止動畫;
  9. 儘可能緩存DOM查找,查找器儘可能簡潔;
  10. 涉及多域名的網站,能夠開啓域名預解析

參考

  1. https://www.cnblogs.com/CandyManPing/p/6635008.html
  2. http://blog.codingplayboy.com/2017/03/29/webpage_render/
相關文章
相關標籤/搜索