從輸入網址列到渲染畫面,過程經歷了什麼事情?
當你在瀏覽器的網址列輸入一個網址(例如 https://www.example.com)並按下 Enter 後,瀏覽器會經過以下幾個主要步驟,將網頁內容呈現在螢幕上:
-
網址解析與 DNS 查詢
-
建立與伺服器的連線
-
發送 HTTP 請求
-
伺服器處理並回傳響應
-
瀏覽器解析 HTML、CSS 和 JavaScript
-
構建 DOM 與 CSSOM
-
渲染樹生成與畫面繪製
-
執行 JavaScript 與互動處理
以下是每個步驟的詳細說明:
1. 網址解析與 DNS 查詢
當你輸入網址(例如 https://www.example.com)並按下 Enter,瀏覽器首先需要知道這個網址對應的伺服器位於哪裡。這個過程涉及以下步驟:
-
解析網址:瀏覽器會解析 URL,分解出協議(https)、域名(www.example.com)、路徑(例如 /index.html)等部分。
-
DNS 查詢:
-
瀏覽器檢查本機的快取(例如本機的 DNS 快取或 hosts 檔案),看看是否已經有這個域名的 IP 地址。
-
如果快取中沒有,瀏覽器會向 DNS 伺服器發送查詢請求,通過域名系統(Domain Name System, DNS)將域名轉換成 IP 地址(例如 93.184.216.34)。
-
DNS 查詢可能會經過多層解析(例如根伺服器、頂級域名伺服器等),最終找到對應的 IP 地址。
-
-
結果:瀏覽器拿到伺服器的 IP 地址,準備與伺服器建立連線。
簡單比喻:這就像你在找一家餐廳的地址,先查手機(快取),如果沒找到,就問導航系統(DNS 伺服器)要怎麼走。
2. 建立與伺服器的連線
有了伺服器的 IP 地址後,瀏覽器需要與伺服器建立連線:
-
TCP 連線:
-
瀏覽器通過 TCP(傳輸控制協議)與伺服器進行三次握手(Three-way Handshake),確保雙方可以穩定傳輸資料。
-
三次握手的簡單流程:
-
客戶端發送 SYN 封包(請求連線)。
-
伺服器回應 SYN-ACK 封包(確認連線)。
-
客戶端再回傳 ACK 封包(確認收到)。
-
-
-
TLS/SSL 握手(若使用 HTTPS):
-
如果網址是 https://,瀏覽器還會與伺服器進行 TLS/SSL 握手,交換加密金鑰,確保資料傳輸安全。
-
這包括驗證伺服器的 SSL 證書,確認網站的真實性。
-
結果:瀏覽器與伺服器之間建立了一個安全的資料通道。
簡單比喻:這就像你打電話給餐廳訂位,先確認對方有沒有接到電話(TCP 握手),然後再確認對方的身份(TLS/SSL 握手)。
3. 發送 HTTP 請求
連線建立後,瀏覽器會向伺服器發送一個 HTTP 請求,告訴伺服器你想要什麼資源:
-
HTTP 請求結構:
-
請求行:包含方法(例如 GET、POST)、路徑(例如 /index.html)和 HTTP 版本(例如 HTTP/1.1 或 HTTP/2)。
-
標頭(Headers):包含瀏覽器資訊(例如 User-Agent)、接受的檔案類型(Accept)、語言偏好等。
-
主體(Body):GET 請求通常沒有主體,POST 請求可能包含表單資料。
-
-
範例請求(以 GET 為例):
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/117.0.0.0
Accept: text/html,application/xhtml+xml
簡單比喻:這就像你告訴餐廳服務生:「我要一份主菜單(index.html),用中文給我。」
4. 伺服器處理並回傳響應
伺服器收到請求後,會處理並回傳一個 HTTP 響應:
-
HTTP 響應結構:
-
狀態行:包含 HTTP 版本和狀態碼(例如 200 OK 表示成功,404 Not Found 表示找不到資源)。
-
標頭(Headers):包含內容類型(Content-Type,例如 text/html)、內容長度(Content-Length)等。
-
主體(Body):包含實際的資源內容,例如 HTML 文件。
-
-
範例響應:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html> -
伺服器處理:
-
伺服器可能會根據請求路徑查找靜態檔案(例如 HTML 文件),或執行後端程式(例如 PHP、Node.js)生成動態內容。
-
如果有快取設定(例如 Cache-Control),伺服器可能會指示瀏覽器使用快取資源。
-
簡單比喻:服務生聽到你的點單後,去廚房拿菜單(HTML 文件)給你。
5. 瀏覽器解析 HTML、CSS 和 JavaScript
收到伺服器的響應後,瀏覽器開始解析回傳的資源:
-
解析 HTML:
-
瀏覽器將 HTML 內容轉換成 DOM(文件物件模型,Document Object Model),這是一棵樹狀結構,代表網頁的結構。
-
例如,
<div><p>Hello</p></div>
會被解析成一個包含<div>
和<p>
節點的樹。
-
-
解析 CSS:
-
如果 HTML 中有
<link>
標籤引用外部 CSS 文件,瀏覽器會下載並解析 CSS,生成 CSSOM(CSS 物件模型,CSS Object Model)。 -
CSSOM 描述了每個元素的樣式規則。
-
-
下載其他資源:
- HTML 中可能包含圖片(
<img>
)、JavaScript(<script>
)或其他資源的引用,瀏覽器會發送額外的 HTTP 請求來下載這些資源。
- HTML 中可能包含圖片(
-
解析 JavaScript:
-
如果有
<script>
標籤,瀏覽器會執行 JavaScript 程式碼。 -
JavaScript 可能會動態修改 DOM 或 CSSOM,例如添加新元素或改變樣式。
-
簡單比喻:這就像你拿到菜單(HTML),開始閱讀上面的內容(解析),並根據菜單上的圖片(CSS)或特別指示(JavaScript)準備餐桌。
6. 構建 DOM 與 CSSOM
這一步是將 HTML 和 CSS 轉換成瀏覽器能理解的結構:
-
DOM 樹:
-
每個 HTML 標籤對應一個節點,父子關係形成樹狀結構。
-
例如:
<html>
<body>
<div>
<p>Hello</p>
</div>
</body>
</html>會生成如下 DOM 樹:
Document
└── html
└── body
└── div
└── p ("Hello")
-
-
CSSOM 樹:
-
CSS 規則被解析成另一棵樹,描述元素的樣式。
-
例如:
div { background: blue; }
p { color: white; }會生成對應的 CSSOM 結構,記錄每個元素的樣式。
-
注意:DOM 和 CSSOM 的構建是並行的,但 JavaScript 的執行可能會阻塞 DOM 解析(除非使用 async 或 defer 屬性)。
簡單比喻:這就像你把菜單(HTML)整理成一張表格(DOM),然後把裝飾風格(CSS)記錄下來,準備用來佈置餐桌。
7. 渲染樹生成與畫面繪製
有了 DOM 和 CSSOM,瀏覽器會將它們結合起來,生成渲染樹(Render Tree),並最終繪製畫面:
-
生成渲染樹:
-
渲染樹是 DOM 和 CSSOM 的結合,只包含需要顯示的元素(例如隱藏的元素,如 display: none,不會出現在渲染樹中)。
-
每個渲染樹節點包含元素的結構和樣式資訊。
-
-
佈局(Layout):
-
瀏覽器計算每個元素的位置和大小(例如寬度、高度、邊距等),這也叫「回流」(Reflow)。
-
例如,確定一個
<div>
在螢幕上的確切位置。
-
-
繪製(Painting):
-
瀏覽器將渲染樹轉換成像素,繪製到螢幕上,包括文字、顏色、邊框、圖片等。
-
這一步由瀏覽器的渲染引擎(例如 Chrome 的 Blink)完成。
-
-
合成(Compositing):
- 現代瀏覽器會將頁面分成多個圖層(Layer),分別繪製後再合成,這樣可以提高效率(特別是在動畫或滾動時)。
簡單比喻:這就像你根據菜單和裝飾風格,把餐桌上的盤子、食物(元素)擺好位置(佈局),然後上色(繪製),最後把所有東西組合起來呈現給客人(合成)。
8. 執行 JavaScript 與互動處理
網頁渲染完成後,JavaScript 程式碼可能會繼續執行,處理用戶互動或動態更新頁面:
-
事件監聽:
-
JavaScript 可以監聽用戶的事件(例如點擊、鍵盤輸入、滑鼠移動)。
-
以下是一個簡單的 JavaScript 範例,監聽按鈕點擊事件:
// 假設 HTML 中有 <button id="myButton">點我</button>
document.getElementById("myButton").addEventListener("click", function () {
alert("你點擊了按鈕!");
});
-
-
動態更新:
-
JavaScript 可以修改 DOM 或 CSSOM,例如動態添加元素:
// 動態添加一個 <p> 元素
const newParagraph = document.createElement("p");
newParagraph.textContent = "這是新添加的段落!";
document.body.appendChild(newParagraph);
-
-
非同步請求:
-
網頁可能通過 AJAX 或 Fetch API 向伺服器請求額外資料,並更新畫面:
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => {
const element = document.getElementById("dataContainer");
element.textContent = data.message; // 假設回傳的資料有 message 欄位
})
.catch((error) => {
console.error("錯誤:", error);
});
-
簡單比喻:這就像餐廳開始營業後,服務生(JavaScript)會根據客人的需求(點擊、輸入)動態調整菜單或佈置。
總結與流程圖
以下是整個過程的簡要流程圖(文字版):
輸入網址 → DNS 查詢 → 建立 TCP/TLS 連線 → 發送 HTTP 請求
→ 伺服器回傳響應 → 解析 HTML/CSS/JS → 構建 DOM 與 CSSOM
→ 生成渲染樹 → 佈局 → 繪製 → 合成 → 執行 JavaScript
關鍵點:
-
每個步驟都可能涉及快取(例如 DNS 快取、瀏覽器快取),以提高效率。
-
JavaScript 的執行可能會影響渲染過程,因此要謹慎使用(例如避免阻塞主線程)。
-
現代瀏覽器會優化渲染流程(例如並行下載資源、使用 GPU 加速繪製)。