瀏覽器渲染原理 (一)在網址中輸入一個網站後面都作了什麼

人法地,地法天,天法道,道法天然。javascript

瀏覽器渲染原理 (一)在網址中輸入一個網站後面都作了什麼css

瀏覽器渲染原理 (二)css、javascript、dom 阻塞關係html

瀏覽器渲染原理 (三) repaint(重繪)和 reflow(迴流)詳解html5

若是想看更深刻的原理,能夠看:java

別人翻譯的外國友人的渲染原理node

瀏覽器是怎麼渲染 html 的

關鍵渲染路徑(Critical Rendering Path)是指與當前用戶操做有關的內容。例如用戶剛剛打開一個頁面,首屏的顯示就是當前用戶操做相關的內容,具體就是瀏覽器收到HTML、CSS 和 JavaScript 等資源並對其進行處理從而渲染出 Web 頁面。 以下圖所示渲染流程: web

bowser-render
當咱們在瀏覽器中輸入一個網址的時候,他是怎麼請求資源,而且把咱們的頁面繪製出來的,大概能夠分爲六步,其中又能夠細分,下面我大概說一個 6 大步驟:

  1. 瀏覽器首先經過 HTTP 協議或者 HTTPS 協議,向服務器請求頁面,固然這個其中也可能有緩存什麼的;
  2. 把請求回來的HTML 代碼通過解析,構建成 DOM 樹;
  3. 計算 DOM 樹上的 CSS 屬性,生成 CSSOM 樹(CSS Object Model)
  4. DOM 樹CSSOM 樹合併成一個渲染樹(rendering tree)
  5. 渲染樹的每一個元素包含的內容都是計算過的,它被稱之爲佈局 layout。瀏覽器使用一種流式處理的方法,只須要一次 pass 繪製操做就能夠佈局全部的元素;
  6. 將渲染樹的各個節點繪製到屏幕上,這一步被稱爲繪製 painting
  7. 按照合理的順序合併圖層而後顯示到屏幕上 Composite(渲染層合併)

第一步請求資源

在咱們在瀏覽器中輸入完網址的時候,瀏覽器其實會先作如下幾小步:瀏覽器

  1. DNS 查詢(就是把當前域名解析成爲 ip 地址)
  2. TCP 鏈接
  3. HTTP 請求響應
  4. 服務器返回數據

第二步構建 DOM 樹

在構建 DOM 樹的時候又能夠分爲幾小步:緩存

  1. 字符流經過狀態機解析成爲 詞 token
  2. token => prase => DOM 樹

構建 DOM 的過程是:從父到子,從先到後,一個一個節點構造,DOM 樹結構和 HTML 標籤一一對應。服務器

第三步 CSSOM 模型構建

在計算 css 規則的時候,咱們會在已經構建好的元素上,去檢查它匹配到了哪些規則,再根據規則的優先級,作覆蓋和調整。而且 CSSOM 主要是DOM 結構上的盒的描述,他基本上是依附於 DOM 樹的。 CSS 計算是把 CSS 規則應用到 DOM 樹上,爲 DOM 結構添加顯示相關屬性過程。 CSSOM 是有 rule 部分和 view 部分的,rule 部分是在 dom 開始以前就構件完成的,而 view 部分是跟着 dom 同步構建的。

第四步構建渲染樹(Rendr tree construction)

經過 DOM 樹CSS 規則樹,瀏覽器就能夠經過它兩構建渲染樹了。 渲染樹DOM 元素相對應的,但並不是一一對應。非可視化的 DOM 元素不會插入呈現樹中,例如「head」元素。若是元素的 display 屬性值爲「none」,那麼也不會顯示在呈現樹中(可是 visibility 屬性值爲「hidden」的元素仍會顯示)。

第五步渲染樹佈局(layout of the render tree)

呈現器在建立完成並添加到呈現樹時,並不包含位置和大小信息。計算這些值的過程稱爲佈局重排。 佈局階段會從渲染樹更新節點開始遍歷,因爲渲染樹的每一個節點都是一個 Render Object 對象,包含寬高,位置,背景色等樣式信息。瀏覽器中渲染這個過程,就是把每個元素對應的盒變成位圖,再把位圖合成一個大的位圖。 佈局又分爲全局佈局和增量佈局,詳情請看

第六步渲染樹繪製(Painting the render tree)

在繪製階段,系統會遍歷呈現樹,並調用呈現器的「paint」方法,將呈現器的內容顯示在屏幕上。繪製工做是使用用戶界面基礎組件完成的。 繪製又分爲全局繪製增量繪製,而且繪製的屬性也會有先後之分,詳情請看

compositor layer 合成渲染層

渲染過程把元素變成位圖,合成把一部分位圖變成合成層,最終的繪製過程把合成層顯示到屏幕上。 對於 transform/opacity 這兩種變換,瀏覽器不會用 repaint/reflow 處理,而是在已經渲染的元素基礎上進行附加工做。 他的渲染流程爲下圖所示:

compositor
js 改變樣式,樣式只觸發合成屬性,不觸發 repaint/reflow.附原文連接 stick-to-compositor-only-properties-and-manage-layer-count

阻塞渲染:CSS、JavaScript、DOM

談論資源的阻塞時,咱們要清楚,現代瀏覽器老是並行加載資源。例如,當 HTML 解析器(HTML Parser)被腳本阻塞時,解析器雖然會中止構建 DOM,但仍會識別該腳本後面的資源,並進行預加載。 同時,因爲下面兩點:

  1. 默認狀況下,CSS 被視爲阻塞渲染的資源,這意味着瀏覽器將不會渲染任何已處理的內容,直至CSSOM 構建完畢
  2. JavaScript 不只能夠讀取和修改 DOM 屬性,還能夠讀取和修改 CSSOM 屬性,所以 CSS 解析script 的執行互斥。
  3. 存在阻塞的 CSS 資源時,瀏覽器會延遲 JavaScript 的執行和 DOM 構建

正是因爲以上這些緣由,script 標籤的位置很重要咱們在實際開發中應該儘可能堅持如下兩個原則: 在引入順序上,CSS 資源先於 JavaScript 資源。 JavaScript 應儘可能少的去影響 DOM 的構建。 想理清楚 CSS、JavaScript、DOM 之間的相互阻塞關係

改變阻塞模式

咱們熟知的javascript標籤上deferasync屬性,還有可能不太熟知的link標籤上的preload屬性。

在介紹 async 和 defer 以前咱們要先看了解兩個概念,loadDOMContentLoaded的執行時機

load 和 DOMContentLoaded

load Load 事件觸發表明頁面中的 DOM,CSS,JS,圖片已經所有加載完畢。 DOMContentLoaded DOMContentLoaded 事件觸發表明初始的 HTML 被徹底加載和解析,不須要等待 CSS,JS,圖片加載。

首先是 async 和 defer

async 和 defer 他們對於內聯腳本無做用(即沒有 src 屬性的腳本) async 該布爾屬性指示瀏覽器是否在容許的狀況下異步執行該腳本。async 與 defer 的區別在於,若是已經加載好,就會開始執行——不管此刻是 HTML 解析階段仍是 DOMContentLoaded 觸發以後。須要注意的是,這種方式加載的 JavaScript 依然會阻塞 load 事件。換句話說,async-script 可能在 DOMContentLoaded 觸發以前或以後執行,但必定在 load 觸發以前執行。而且多個 async-script 的執行順序是不肯定的。

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

defer 與相比普通 script,有兩點區別:載入 JavaScript 文件時不阻塞 HTML 的解析,執行階段被放到 HTML 標籤解析完成以後。

preload 和 prerender

preload

<link> 元素的 rel 屬性的屬性值preload可以讓你在你的HTML頁面<head>元素內部書寫一些聲明式的資源獲取請求,能夠指明哪些資源是在頁面加載完成後即刻須要的。對於這種即刻須要的資源,你可能但願在頁面加載的生命週期的早期階段就開始獲取,在瀏覽器的主渲染機制介入前就進行預加載。這一機制使得資源能夠更早的獲得加載並可用,且更不易阻塞頁面的初步渲染,進而提高性能。 預加載能夠必定程度上下降首屏的加載時間,由於能夠將一些不影響首屏但重要的文件延後加載,惟一缺點就是兼容性很差.

prerender 能夠經過預渲染將下載的文件預先在後臺渲染,可使用如下代碼開啓預渲染 預渲染雖然能夠提升頁面的加載速度,可是要確保該頁面百分百會被用戶在以後打開,不然就白白浪費資源去渲染

總結

這個裏面基本上了解了瀏覽器的渲染過程,可是有不少細節沒有套路好比說咱們都知道瀏覽器是單線程的,ui 線程javascript 線程是怎麼協調的,還有一個比較重要的是重繪和迴流(重排)

參考

瀏覽器的渲染:過程與原理

瀏覽器渲染原理與過程

HTML、script元素用於嵌入或引用可執行腳本。

瀏覽器的工做原理:新式網絡瀏覽器幕後揭祕

重繪,迴流和合成,瞭解基本瀏覽器繪製幫你優化頁面性能

相關文章
相關標籤/搜索