你有沒有想過,當你輸入一個 URL 並按下 Enter 鍵時,瀏覽器背後究竟發生了什麼事?從外部看,這一切看似簡單,但背後卻隱藏著一個非常複雜的工程流程,涉及多個步驟、層級和協定。在本文中,我們將探索瀏覽器的工作原理及其內部架構的設計。

瀏覽器的元件

一個瀏覽器可以理解分成幾個重要的部分:

使用者介面 (UI):與使用者互動的層,指您直接看到和互動的一切,例如網址列、導覽按鈕和標籤。

瀏覽器引擎:瀏覽器的核心引擎。它將使用者介面與其他瀏覽器元件連接起來。它還負責資料持久化(Cookie、快取、本地儲存)並與渲染引擎進行通訊。

渲染引擎:負責在螢幕上渲染內容。該元件與 JS 解釋器和網路層協同工作,將 HTML、CSS 和 JavaScript 轉換為可見像素。

網路:管理 HTTP/HTTPS 請求、DNS 解析、cookie、快取、資料壓縮以及連接的所有安全措施。

JavaScript 解釋器:解析、編譯並執行 JS 程式碼:解析、建立抽象語法樹 (AST)、轉換為字節碼、套用 JIT 最佳化並在 JS 虛擬機器上執行。這支援 DOM 操作、事件處理和頁面互動。

資料持久性:允許瀏覽器在本機上儲存和檢索資料,確保使用者資料、設定和首選項在會話期間得到維護。

圖片描述

值得注意的是,瀏覽器基本上是單線程的。這意味著只有一個主執行緒控制流程,這在討論效能時至關重要。為了克服這一限制,瀏覽器使用了諸如事件循環之類的機制,這與我們在 Node.js 中了解到的機制非常相似。

當我們輸入 URL 時會發生什麼?

輸入 URL 並按下 Enter 鍵後,將發生以下步驟:

網域解析(DNS):

第一步是將網域名稱(例如 google.com)轉換為 IP 位址。瀏覽器會檢查各種快取(瀏覽器、作業系統、路由器、ISP)。

如果找不到,它會查詢 DNS 伺服器,DNS 伺服器會傳回正確的 IP。

伺服器連線(TCP握手):

取得IP後,瀏覽器透過TCP三次握手建立連線:

SYN→SYN-ACK→ACK。

可以將其視為開始電話交談的數位等價物。

使用 TLS 握手的安全性:

在交換資料之前,必須建立安全的加密金鑰。這涉及客戶端和伺服器之間的多次訊息交換,以確保流量不會被攔截。

邊緣運算和CDN:

為了加快這一速度,Google、Netflix 和亞馬遜等公司在全球範圍內使用 CDN 和邊緣位置,以減少用戶和伺服器之間的延遲。

首次回應 – TTFB:

一切設定完成後,瀏覽器會收到第一個位元組(第一個位元組時間)。甚至在完整頁面載入完成之前,渲染就開始了。

解析和關鍵渲染路徑

當瀏覽器收到初始 HTML 時,它開始解析。過程包括:

DOM 建構:HTML 被轉換為稱為文件物件模型的樹狀結構。

圖片描述

CSSOM 建構:CSS 也被解析成一棵樹,也就是 CSS 物件模型。與 DOM 不同,它必須完全建造後才能繼續。

渲染樹:DOM + CSSOM 組合成渲染樹,其中僅包含具有計算樣式的可見元素。

佈局:決定螢幕上每個元素的位置和大小。

繪畫:最後,在螢幕上繪製像素。

此流程稱為關鍵渲染路徑 (CRP)。腳本可能會阻塞 DOM 建置,樣式可能會延遲 CSSOM 建置。因此,腳本的 async 和 defer 等技術可以提高載入速度。

預載掃描儀

在建置 DOM 時,瀏覽器會執行預先載入掃描器,它會尋找 HTML 中引用的外部資源(圖片、腳本、樣式)。這些資源會提前下載,從而減少整體渲染時間。

JavaScript 和 AST

與編譯型語言不同,JavaScript 是解釋型語言,但現代瀏覽器對執行進行了最佳化:

解析:程式碼被解析為抽象語法樹(AST)。

圖片描述

字節碼和 JIT:AST 被轉換為字節碼,由即時 (JIT) 編譯器最佳化,然後由 JS 虛擬機器執行。

執行:延遲和阻塞腳本僅在 HTML 和 CSS 準備好後執行,以確保更快的初始渲染。

DOM 詳解

HTML 文件可以在記憶體中表示為 JavaScript 樹(節點和子節點)。這使得框架、庫和開發人員可以即時操作頁面。

例子:

const domTree = {
  nodeType: 'document',
  children: [
    { nodeType: 'doctype', name: 'html' },
    {
      tagName: 'html',
      attributes: { lang: 'en' },
      children: [
        {
          tagName: 'head',
          children: [
            { tagName: 'meta', attributes: { charset: 'utf-8' }, children: [] },
            { tagName: 'meta', attributes: { name: 'viewport', content: 'width=device-width, initial-scale=1' }, children: [] },
            { tagName: 'title', children: [{ type: 'text', content: 'Page Title' }] },
            { tagName: 'link', attributes: { rel: 'stylesheet', href: '/styles.css' }, children: [] },
            { tagName: 'script', attributes: { src: '/scripts/head.js', defer: true }, children: [] }
          ]
        },
        {
          tagName: 'body',
          children: [
            {
              tagName: 'header',
              children: [
                { tagName: 'h1', children: [{ type: 'text', content: 'Main Header' }] },
                {
                  tagName: 'nav',
                  children: [
                    {
                      tagName: 'ul',
                      children: [
                        { tagName: 'li', children: [{ tagName: 'a', attributes: { href: '/' }, children: [{ type: 'text', content: 'Home' }] }] },
                        { tagName: 'li', children: [{ tagName: 'a', attributes: { href: '/about' }, children: [{ type: 'text', content: 'About' }] }] }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              tagName: 'main',
              children: [
                {
                  tagName: 'article',
                  attributes: { id: 'post-1' },
                  children: [
                    { tagName: 'h2', children: [{ type: 'text', content: 'Article Title' }] },
                    { tagName: 'p', children: [{ type: 'text', content: 'First paragraph of the article.' }] },
                    { tagName: 'img', attributes: { src: '/img/photo.jpg', alt: 'Photo' }, children: [] }
                  ]
                },
                {
                  tagName: 'section',
                  attributes: { id: 'features' },
                  children: [
                    { tagName: 'h3', children: [{ type: 'text', content: 'Features Section' }] },
                    {
                      tagName: 'ul',
                      children: [
                        { tagName: 'li', children: [{ type: 'text', content: 'Feature A' }] },
                        { tagName: 'li', children: [{ type: 'text', content: 'Feature B' }] }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              tagName: 'aside',
              children: [
                { tagName: 'h4', children: [{ type: 'text', content: 'Sidebar' }] },
                { tagName: 'p', children: [{ type: 'text', content: 'Supporting content / widgets.' }] }
              ]
            },
            {
              tagName: 'footer',
              children: [
                { tagName: 'p', children: [{ type: 'text', content: '© 2025 My Company' }] },
                { tagName: 'ul', children: [{ tagName: 'li', children: [{ tagName: 'a', attributes: { href: '/privacy' }, children: [{ type: 'text', content: 'Privacy Policy' }] }] }] }
              ]
            },
            { tagName: 'script', attributes: { src: '/scripts/bundle.js' }, children: [] }
          ]
        }
      ]
    }
  ]
};

此外,DOM 並非靜態的。瀏覽器可能會在下載新資源的同時逐步建立它。這使得 DOM 成為一個即時的動態結構,完全可以透過 JavaScript API 進行操作。

結論

為了呈現單一網頁,瀏覽器需要經歷一個龐大的過程,其中包括:

  • 解析域名

  • 執行多次握手

  • 處理安全協議

  • 建立 DOM 和 CSSOM 樹

  • 產生渲染樹、佈局和繪製

  • 執行優化的 JavaScript

所有這些都發生在幾分之一秒內。本文的靈感來自 Augusto Galego 的精彩影片《瀏覽器是如何運作的? 》,他在影片中以清晰易懂的方式解釋了這些主題。當然,瀏覽器功能還涉及許多其他層面,從頭開始建立一個瀏覽器將是一項極其複雜的任務。

如果你讀到這裡,非常感謝!任何回饋都將不勝感激。


原文出處:https://dev.to/giovanni786/how-a-web-browser-works-inside-modern-browsers-3j8d


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝10   💬6   ❤️11
459
🥈
我愛JS
📝1   💬5   ❤️4
89
🥉
AppleLily
📝1   💬4   ❤️1
47
#4
💬2  
6
#5
💬1  
5
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次