瀏覽器頁面渲染機制

分享目的: 解釋瀏覽器如何將 HTML、CSS 和 JavaScript 轉換爲咱們能夠與之交互的網站,瞭解這個過程,能夠幫助咱們優化 Web 應用程序,從而得到更快的速度和更好的性能。

問題: 瀏覽器如何渲染網站? (接下來會解構這個過程,可是首先,有必要了解一些基礎概念)

Web 瀏覽器是一種軟件,它從遠程服務器(或者本地磁盤)加載文件並將其顯示——使用戶能夠與之交互。瀏覽器中有一個軟件叫瀏覽器引擎。在不一樣的瀏覽器中,瀏覽器的某個部分會根據它接收到的文件肯定顯示什麼,這就是所謂的瀏覽器引擎。瀏覽器引擎是每一種主流瀏覽器的核心軟件組件,不一樣的瀏覽器開發商用不一樣的名字來稱呼他們的引擎。javascript

1. html解析

  • 接收信息
    數據是以「數據包」的形式經過互聯網發送,而數據包以字節爲單位。當你編寫一些 HTML、CSS 和 JS,並試圖在瀏覽器中打開 HTML 文件時,瀏覽器會從你的硬盤(或網絡)中讀取 HTML 的原始字節。
  • 計算機接收到字節數據
    瀏覽器讀取的是原始數據字節,而不是你編寫的代碼的實際字符。瀏覽器讀取的是原始數據字節,而不是你編寫的代碼的實際字符。
  • 從 HTML 的原始字節到 DOM,瀏覽器對象須要處理的是文檔對象模型(DOM)對象。那麼,DOM 對象是從何而來的呢?首先,將原始數據字節轉換爲字符。(Bytes => haracters)
  • 從字節到字符
    這一點,你能夠經過你所編寫的代碼的字符看到。這種轉換是基於 HTML 文件的字符編碼完成的。至此,瀏覽器已經從原始數據字節轉換爲文件中的實際字符。但這不是最終的結果。這些字符會被進一步解析爲一些稱爲「標記(token)」的東西。(Bytes => haracters => Tokens···)
  • 從字符到標記
    那麼,這些標記是什麼?文本文件中的一堆字符對瀏覽器引擎而言沒什麼用處。若是沒有這個標記化過程,那麼這一堆堆字符只會生成一系列毫無心義的文本,即 HTML 代碼——不會生成一個真正的網站。 當你保存一個擴展名爲.html 的文件時,就向瀏覽器引擎發出了把文件解析爲 HTML 文檔的信號。瀏覽器「解釋」這個文件的方式是首先解析它。在解析過程當中,特別是在標記化過程當中,瀏覽器會解析 HTML 文件中的每一個開始和結束「標籤(tag)」。解析器能夠識別尖括號中的每一個字符串,如「< html>」、「< p>」

但標記還不是最終的結果。標記化完成後,接下來,標記將被轉換爲節點。你能夠將節點看做是具備特定屬性的不一樣對象。實際上,更好的解釋是,將節點看做是文檔對象樹中的獨立實體。但節點仍然不是最終結果。 如今,讓咱們看一下最後一點。在建立好以後,這些節點將被連接到稱爲DOM 的樹數據結構中。DOM 創建起了父子關係、相鄰兄弟關係等。在這個 DOM 對象中,每一個節點之間都創建了關係。如今,這是咱們可使用的東西了。css

  • 標記
    但標記還不是最終的結果。標記化完成後,接下來,標記將被轉換爲節點。你能夠將節點看做是具備特定屬性的不一樣對象。實際上,更好的解釋是,將節點看做是文檔對象樹中的獨立實體。但節點仍然不是最終結果。
  • DOM (Bytes => haracters => Tokens => Node => DOM) 讓咱們看一下最後一點。在建立好以後,這些節點將被連接到稱爲 DOM 的樹數據結構中。DOM 創建起了父子關係、相鄰兄弟關係等。在這個 DOM 對象中,每一個節點之間都創建了關係。這個時候,是瀏覽器須要的東西了。

2.css解析

這個是咱們很常見的寫法html

<!DOCTYPE html>
<html> <head> <link rel="stylesheet" type="text/css" href="test.css" /> </head> <body> </body> </html> 複製代碼

當瀏覽器接收到原始數據字節並啓動 DOM 構建過程時,它還會發出請求來獲取連接的 test.css 樣式表。當瀏覽器開始解析 HTML 時,在找到 css 文件的連接標籤的同時,它會發出請求來獲取它。可能你已經猜到,瀏覽器仍是接收 CSS 數據的原始字節,從互聯網或是本地磁盤。java

瀏覽器如何處理這些 CSS 數據的原始字節?

當瀏覽器接收到 CSS 的原始字節時,會啓動一個和處理 HTML 原始字節相似的過程。就是說,原始數據字節被轉換成字符,而後標記,而後造成節點,最後造成樹結構。 什麼是樹結構?大多數人都知道 DOM 這個詞。一樣,也有一種 CSS 樹結構,,瀏覽器不能使用 HTML 或 CSS 的原始字節。必須將其轉換成它能識別的形式,也就是這些樹形結構。瀏覽器

DOM + CSSOM = 渲染樹

渲染樹包含頁面上全部關於可見 DOM 內容的信息以及不一樣節點所需的全部 CSSOM 信息。注意,若是一個元素被 CSS 隱藏,例如使用 display; none,那麼節點就不會包含在渲染樹中。隱藏元素會出如今 DOM 中,但不會出如今渲染樹中。這是由於渲染樹結合了來自 DOM 和 CSSOM 的信息,因此它知道不能把隱藏元素包含在樹中。服務器

元素展現

咱們已經獲得了在屏幕上顯示元素所需的全部信息。咱們只要把它展現給用戶。這就是這個階段的所有工做。有了元素內容(DOM)、樣式(CSSOM)和計算得出的元素的精確佈局信息,瀏覽器如今就能夠將節點逐個「繪製」到屏幕上了。元素能夠呈如今屏幕上了!markdown


渲染阻塞資源

通俗的解釋爲有東西阻止了屏幕上節點的實際繪製,在成功繪製以前,必須構造 DOM 和 CSSOM,所以,HTML 和 CSS 都是渲染阻塞資源。網絡

  • JavaScript 如何執行?
    一個經常使用的 Web 應用程序確定會使用一些 JavaScript。這是必定的。JavaScript 的「問題」在於你可使用 JavaScript 修改頁面的內容和樣式。經過這種方式,你能夠從 DOM 樹中刪除元素和添加元素,還能夠經過 JavaScript 修改元素的 CSSOM 屬性。這很方便,可是同時也帶來了弊端
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <p>瀏覽器頁面渲染機制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
複製代碼

這是一個很是常見的文檔。樣式表 style.css簡單定義樣式:數據結構

* {
  font-size: 20px;
}
body {
  background-color: antiquewhite;
}
複製代碼

一段簡單的文本和圖像呈如今屏幕上。async

根據前面的解釋,瀏覽器從磁盤(或網絡)讀取 HTML 文件的原始字節並將其轉換爲字符。字符被進一步解析爲標記。當解析器遇到< link rel="stylesheet" href="style.css">時,就會請求獲取 CSS 文件 style.css。DOM 構造繼續進行,當 CSS 文件返回一些內容後,CSSOM 構造就開始了。

  • 引入 JavaScript
    每當瀏覽器遇到腳本標籤時,DOM 構造就會暫停!整個 DOM 構建過程都將中止,直到腳本執行完成。JavaScript 能夠同時修改 DOM 和 CSSOM。因爲瀏覽器不肯定特定的 JavaScript 會作什麼,因此它採起的預防措施是中止整個 DOM 構造。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <p id="title">瀏覽器頁面渲染機制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
  <script>
      let title = document.getElementById("title");
      console.log("title is: ", title);
  </script>
</body>
</html>
複製代碼

當把js放到元素以前的話

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>testRander</title>
 <link rel="stylesheet" href="style.css">
</head>
<body>
   <script>
       let title = document.getElementById("title");
       console.log("title is: ", title);
   </script>
 <p id="title">瀏覽器頁面渲染機制</p>
 <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
複製代碼

當腳本試圖訪問一個 id 爲 header 的 DOM 節點時,因爲 DOM 尚未完成對文檔的解析,因此它還不存在。這把咱們帶到了另外一個重要的問題。腳本的位置很重要。

在默認狀況下,每一個腳本都是一個解析器阻斷器!DOM 的構建老是會被打斷。不過,有一種方法能夠改變這種默認行爲。若是將 async 關鍵字添加到腳本標籤中,那麼 DOM 構造就不會中止。DOM 構造將繼續,腳本將在下載完成並準備就緒後執行。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>testRander</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <script src="test.js" async></script>
  <p id="title">瀏覽器頁面渲染機制</p>
  <img src="http://spage.haimati.cn/activityImage/newplan.jpg">
</body>
</html>
複製代碼

把js放入test.js中進行引入

let title = document.getElementById("title");
console.log("title is: ", title);
複製代碼

這樣DOM的構建就不會中止,腳本在構造完成後執行。

相關文章
相關標籤/搜索