瀏覽器工作原理深度解析(階段二):HTML 解析與 DOM 樹構建

一、引言

在階段一中,我們了解了瀏覽器通過 HTTP/HTTPS 協議獲取頁面資源的過程。本階段將聚焦于瀏覽器如何解析 HTML 代碼并構建 DOM 樹,這是渲染引擎的核心功能之一。該過程可分為兩個關鍵步驟:詞法分析(Token 化)和語法分析(DOM 構建)。

二、HTML 解析核心流程

1. 詞法分析:字符流到 Token 的轉換

狀態機實現
瀏覽器通過狀態機將字符流轉換為 Token。例如,當遇到<時進入標簽狀態,根據后續字符判斷是開始標簽、結束標簽還是注釋。以下是狀態機的簡化實現:

function tagOpenState(c) {if (c === '/') return endTagOpenState;if (c.match(/[A-Za-z]/)) {const token = new StartTagToken();token.name = c.toLowerCase();return tagNameState;}// 其他狀態處理...
}

常見 Token 類型

Token 類型示例說明
開始標簽<p包含標簽名和屬性
結束標簽</p>閉合對應開始標簽
文本節點text content標簽內的文本內容
注釋節點<!-- comment -->被解析器忽略的注釋內容

2. 語法分析:棧驅動的 DOM 構建

棧結構管理

function HTMLSyntaticalParser() {let stack = [new HTMLDocument()];this.receiveInput = (token) => {if (token.type === 'startTag') {const element = new Element(token.name);stack[stack.length-1].childNodes.push(element);stack.push(element);} else if (token.type === 'endTag') {stack.pop();}// 文本節點合并邏輯...};
}

構建規則

  • 開始標簽創建新節點并入棧
  • 結束標簽彈出棧頂節點
  • 文本節點合并相鄰節點(連續文本合并為一個節點)

容錯處理
當遇到不匹配的標簽(如</div>對應<p>),瀏覽器會自動調整棧結構,確保 DOM 樹完整性。例如:

<div><p></div>

解析時會自動閉合</p>標簽,最終 DOM 結構為:

<div><p></p>
</div>

三、瀏覽器優化技術

1. 增量式解析

瀏覽器采用流式解析,無需等待完整 HTML 下載即可開始渲染。例如:

<!DOCTYPE html>
<html>
<head><title>Example</title><style>body { color: red; }</style>
</head>
<body><h1>Hello World</h1><p>Streamed content starts here...

解析器在下載到h1標簽時就開始構建 DOM 樹,同時 CSS 解析器并行處理樣式規則。

2. 預解析與資源加載

  • 預加載掃描:解析 HTML 時同步解析<link><script>標簽
  • 優先級調度:關鍵資源(如首屏 CSS)優先加載
  • 推測加載:根據頁面結構預判可能需要的資源(如圖片、字體)

四、實踐案例:實現簡易 HTML 解析器

1. 詞法分析器

class Lexer {constructor(input) {this.input = input;this.pos = 0;}nextToken() {while (this.pos < this.input.length) {const c = this.input[this.pos];if (c === '<') {this.pos++;return { type: 'tagStart', value: this.consumeTagName() };}// 處理文本節點...}}consumeTagName() {let name = '';while (this.pos < this.input.length && /[A-Za-z]/.test(this.input[this.pos])) {name += this.input[this.pos++];}return name;}
}

2. 語法分析器

class Parser {constructor(lexer) {this.lexer = lexer;this.stack = [new Document()];}parse() {let token;while (token = this.lexer.nextToken()) {if (token.type === 'tagStart') {const element = new Element(token.value);this.stack[this.stack.length-1].children.push(element);this.stack.push(element);} else if (token.type === 'tagEnd') {this.stack.pop();}}return this.stack[0];}
}

五、性能優化策略

1. 減少重排與重繪

  • 批量修改 DOM:使用文檔片段(DocumentFragment)
  • CSS 優化:避免觸發強制同步布局(如 offsetTop、scrollHeight)
  • GPU 加速:利用 transform 和 opacity 屬性

2. 解析性能優化

  • 預加載關鍵資源:使用<link rel="preload">
  • 減少 DOM 深度:控制嵌套層級在 6 層以內
  • 按需渲染:使用 Intersection Observer 懶加載

六、常見問題與解決方案

Q1:為什么解析速度會變慢?

  • 可能原因:復雜的 CSS 選擇器、大量 DOM 節點
  • 解決方案:使用 Chrome DevTools 的 Performance 面板分析關鍵渲染路徑

Q2:如何處理 HTML 語法錯誤?

// 錯誤恢復機制示例
try {parser.parse();
} catch (e) {console.error('Parsing error:', e);// 重置狀態繼續解析parser.reset();
}

Q3:如何驗證 DOM 樹正確性?

// 驗證父子關系
function validateDOM(node, parent) {if (node.parent !== parent) {throw new Error('DOM樹結構錯誤');}node.children.forEach(child => validateDOM(child, node));
}

七、總結

本階段我們深入探討了瀏覽器解析 HTML 并構建 DOM 樹的核心機制。通過狀態機實現的詞法分析和棧驅動的語法分析,瀏覽器能夠高效處理 HTML 代碼并生成結構化的 DOM 樹。理解這些過程對前端性能優化和復雜問題排查具有重要意義。下一階段將聚焦 CSS 解析、布局計算和渲染流水線等核心機制。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73010.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73010.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73010.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

The Illustrated Stable Diffusion

The Illustrated Stable Diffusion 1. The components of Stable Diffusion1.1. Image information creator1.2. Image Decoder 2. What is Diffusion anyway?2.1. How does Diffusion work?2.2. Painting images by removing noise 3. Speed Boost: Diffusion on compressed…

yarn 裝包時 package里包含sqlite3@5.0.2報錯

yarn 裝包時 package里包含sqlite35.0.2報錯 解決方案&#xff1a; 第一步&#xff1a; 刪除package.json里的sqlite35.0.2 第二步&#xff1a; 裝包&#xff0c;或者增加其他的npm包 第三步&#xff1a; 在package.json里增加sqlite35.0.2&#xff0c;并運行yarn裝包 此…

一個免費 好用的pdf在線處理工具

pdf24 doc2x 相比上面能更好的支持數學公式。但是收費

buu-bjdctf_2020_babystack2-好久不見51

整數溢出漏洞 將nbytes設置為-1就會回繞&#xff0c;變成超大整數 從而實現棧溢出漏洞 環境有問題 from pwn import *# 連接到遠程服務器 p remote("node5.buuoj.cn", 28526)# 定義后門地址 backdoor 0x400726# 發送初始輸入 p.sendlineafter(b"your name…

DHCP 配置

? 最近發現&#xff0c;自己使用虛擬機建立的集群&#xff0c;在斷電關機或者關機一段時間后&#xff0c;集群之間的鏈接散了&#xff0c;并且節點自身的 IP 也發生了變化&#xff0c;發現是 DHCP 的問題&#xff0c;這里記錄一下。 DHCP ? DHCP&#xff08;Dynamic Host C…

股指期貨合約的命名規則是怎樣的?

股指期貨合約的命名規則其實很簡單&#xff0c;主要由兩部分組成&#xff1a;合約代碼和到期月份。 股指期貨合約4個字母數字背后的秘密 股指期貨合約一般來說都是由字母和數字來組合的&#xff0c;包含了品種代碼和到期的時間&#xff0c;下面我們具體來看看。 咱們以“IF23…

OSPF 協議詳解:從概念原理到配置實踐的全網互通實現

什么是OSPF OSPF&#xff08;開放最短路徑優先&#xff09;是由IETF開發的基于鏈路狀態的自治系統內部路由協議&#xff0c;用來代替存在一些問題的RIP協議。與距離矢量協議不同&#xff0c;鏈路狀態路由協議關心網絡中鏈路活接口的狀態&#xff08;包括UP、DOWN、IP地址、掩碼…

深入探究 JVM 堆的垃圾回收機制(二)— 回收

GC Roots 枚舉需要遍歷整個應用程序的上下文&#xff0c;而在進行可達性分析或者垃圾回收時&#xff0c;如果我們還是進行全堆掃描及收集&#xff0c;那么會非常耗時。JVM 將堆分為新生代及老生代&#xff0c;它們的回收頻率及算法不一樣。 1 回收算法 在進行可達性分析時&am…

藍橋杯 之 數論

文章目錄 習題質數找素數 數論&#xff0c;就是一些數學問題&#xff0c;藍橋杯十分喜歡考察&#xff0c;常見的數論的問題有&#xff1a;取模&#xff0c;同余&#xff0c;大整數分解&#xff0c;素數&#xff0c;質因數&#xff0c;最大公約數&#xff0c;最小公倍數等等 素…

Unity Shader編程】之渲染流程之深度及pass詳解

關于透明物體的渲染&#xff0c;首先需要了解以下部分 深度緩沖區深度寫入深度測試pass渲染和深度測試的過程深度測試和顏色混合過程 ** 一&#xff0c;深度緩沖區 ** 深度即物體距離相機的距離&#xff0c;深度寫入即是把物體的距離相機信息記錄下來&#xff0c;寫入一個名…

csv文件格式和excel數據格式有什么區別

CSV&#xff08;Comma-Separated Values&#xff09;和Excel&#xff08;XLS/XLSX&#xff09;數據格式的主要區別如下&#xff1a; 1. 文件格式 CSV&#xff1a;純文本格式&#xff0c;每一行表示一條記錄&#xff0c;字段之間用逗號&#xff08;,&#xff09;或其他分隔符&…

Beans模塊之工廠模塊注解模塊@Qualifier

博主介紹&#xff1a;?全網粉絲5W&#xff0c;全棧開發工程師&#xff0c;從事多年軟件開發&#xff0c;在大廠呆過。持有軟件中級、六級等證書。可提供微服務項目搭建與畢業項目實戰&#xff0c;博主也曾寫過優秀論文&#xff0c;查重率極低&#xff0c;在這方面有豐富的經驗…

C# HTTP 文件上傳、下載服務器

程序需要管理員權限&#xff0c;vs需要管理員打開 首次運行需要執行以下命令注冊URL&#xff08;管理員命令行&#xff09; netsh advfirewall firewall add rule name"FileShare" dirin actionallow protocolTCP localport8000 ipconfig | findstr "IPv4&quo…

基于 TRIZ 理論的筏式養殖吊籠清洗裝備設計研究

基于 TRIZ 理論的筏式養殖吊籠清洗裝備設計研究 一、引言 筏式養殖在水產養殖業中占據重要地位&#xff0c;吊籠作為養殖貝類、藻類等生物的關鍵器具&#xff0c;其清潔程度直接影響養殖生物的健康與產量。傳統的吊籠清洗方式多依賴人工&#xff0c;效率低下、勞動強度大且清洗…

QA:備份產品的存儲架構采用集中式和分布式的優劣?

分布式和集中式各有優劣&#xff0c;且這兩者下面的存儲類型也都不盡相同&#xff0c;從備份與恢復的數據層面來看&#xff0c;這兩者存儲相結合才是優解。 眾所周知&#xff0c;備份數據只存一份還只放在一個存儲里是不現實的。假設把備份數據訪問頻率、生命周期等參數分為三個…

FPGA中串行執行方式之計數器控制

FPGA中串行執行方式之計數器控制 使用計數器控制的方式實現狀態機是一種簡單且直觀的方法。它通過計數器的值來控制狀態的變化,從而實現順序邏輯。計數器的方式特別適合狀態較少且狀態轉移是固定的場景。 基本原理 計數器控制的狀態機 ?例程1:簡單的順序狀態機 以下是一個…

純vue手寫流程組件

前言 網上有很多的vue的流程組件&#xff0c;但是本人不喜歡很多冗余的代碼&#xff0c;喜歡動手敲代碼&#xff1b;剛開始寫的時候&#xff0c;確實沒法下筆&#xff0c;最后一層一層剝離&#xff0c;總算實現了&#xff1b;大家可以參考我寫的代碼&#xff0c;可以拿過去定制…

數字化轉型驅動衛生用品安全革新

當315晚會上晃動的暗訪鏡頭揭露衛生巾生產車間里漂浮的異物、紙尿褲原料倉中霉變的碎屑時&#xff0c;這一觸目驚心的場景無情地撕開了“貼身安全”的遮羞布&#xff0c;暴露的不僅是部分企業的道德缺失&#xff0c;更凸顯了當前檢測與監管體系的漏洞&#xff0c;為整個行業敲響…

【C++】:異常

目錄 C語言處理錯誤的方式 C異常的概念 C異常的使用 異常的拋出與捕獲匹配原則 函數調用鏈中的棧展開 異常重新拋出 異常安全 異常規范 標準庫異常體系 自定義異常體系 異常的優缺點 C語言處理錯誤的方式 返回值檢查&#xff1a;函數返回特定錯誤碼或值標識失敗&am…

SZU軟件工程大學生涯 2022~2026

用于個人面試前自我介紹&#xff0c;防止忘記或談吐不流利。 面試官您好&#xff0c;我是來自深圳大學計算機與軟件學院的軟件工程專業的王雅賢。在校期間&#xff0c;我修讀了程序設計基礎、面向對象程序設計、數據結構、算法分析與設計、操作系統等核心課程&#xff0c;系統…