回顧瀏覽器工作流程
在從下載資源到渲染頁面的瀏覽器工作流程第一部分,我們回顧了當使用者輸入網址並按下 Enter 鍵後,瀏覽器背後的工作流程。接著在從下載資源到渲染頁面的瀏覽器工作流程第二部分,我們回顧了瀏覽器如何處理請求和回應的詳細過程。 現在,是時候深入探討瀏覽器的渲染 pipeline 了。
HTML 解析
在 TCP 連接建立並接收到 HTTP/HTTPS 回應後,瀏覽器會向伺服器請求 HTML 資源,然後開始解析 HTML,並將 HTML 轉換成 DOM 樹(DOM tree)。 當遇到外部 CSS、內部 CSS 或行內樣式時,瀏覽器會立即解析它們嗎?還是等待 HTML 解析完成?或者兩者都有?
CSS 解析
外部 CSS(link 標籤)
當 CSS 透過 link 標籤載入時,預設會阻擋渲染,但不會阻擋 HTML 解析與 DOM 建構。
<link rel="stylesheet" href="style.css" />內部 CSS(style 標籤)
當 CSS 在 style 標籤內時,不會阻擋 HTML 解析與 DOM 建構,因為它已經是 HTML 的一部分,所以不需要額外下載。
<style>
...;
</style>行內 CSS(style 屬性)
當 CSS 在 style 屬性內時,不會阻擋 HTML 解析與 DOM 建構,因為它已經是 DOM 的一部分。 所以我們可以說,無論 CSS 是透過 link 標籤、style 標籤或行內樣式載入,都不會阻擋 HTML 解析與 DOM 建構,它們是平行處理的(意味著它們不會互相阻擋)。 就像 HTML 一樣,瀏覽器會解析這些 CSS 資源並將它們轉換成 CSSOM 樹(CSS 物件模型)。
<div style="color: red;">...</div>HTML 下載 -> DOM 建構
-> 外部 CSS 下載 -> CSS 解析 -> CSSOM 建構 -> 渲染樹 -> 渲染
-> 內部 CSS 解析 -^
-> 行內 CSS 解析 --^JavaScript 解析
JavaScript 比 HTML 和 CSS 複雜得多,因為 JS 可以操作 DOM 和 CSSOM,載入 JS 有三種方式:
一般 script 標籤(沒有 defer 或 async)
<script src="script.js"></script>當 JS 透過 script 標籤載入時,會阻擋 HTML 解析,且需要等待先前的 CSS 下載、解析和完成 CSSOM 建構。
Defer script 標籤
<script src="script.js" defer></script>會等待 HTML 解析和 DOM 建構、CSS 下載、解析和 CSSOM 建構。
注意:具有 type="module" 的 Script 標籤預設會自動使用 defer。
Async script 標籤
<script src="script.js" async></script>不會阻擋 HTML 解析,當 JS 下載完成後,會立即執行,不會等待先前的 CSS 下載、解析和 CSSOM 建構,所以它可以在 DOM 尚未準備好時執行。
何時使用 defer 與 async?
- 操作 DOM 的腳本。
- 需要按特定順序執行的多個腳本。
- 加速初始頁面載入。
async 使用案例
- 獨立功能的腳本。
- 追蹤和分析腳本。
- 廣告腳本。
結論
- 瀏覽器會先請求 HTML 資源,然後解析 HTML 並建構 DOM 樹。
- 當遇到外部 CSS、內部 CSS 或行內樣式時,瀏覽器會解析它們並建構 CSSOM 樹,這會阻擋渲染,但不會阻擋 HTML 解析與 DOM 建構。
- 當遇到 JS 時,取決於 script 標籤的屬性:
- 如果是一般 script 標籤,會阻擋 HTML 解析與 DOM 建構。
- 如果是 defer script 標籤,會等待 HTML 解析與 DOM 建構,並按順序執行。
- 如果是 async script 標籤,下載完成後立即執行,不會阻擋 HTML 解析與 DOM 建構,可能會在存取 DOM 和 CSSOM 時遇到錯誤。