国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

瀏覽器將標簽轉成 DOM 的過程

LancerComet / 2405人閱讀

摘要:在這些罕見的情況下,解析器必須重新啟動,丟棄之前解碼的內容。標簽包含解析器必須收集的文本,然后發送到腳本引擎進行評估。如果文件內調用了,解析器將重新開始解析過程。事件當解析器完成時,它通過一個名為的事件宣布完成。

瀏覽器基本的工作流程

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!

進入主話題之前,先羅列一下瀏覽器的主要構成:

用戶界面- 包括地址欄、后退/前進按鈕、書簽目錄等,也就是你所看到的除了用來顯示你所請求頁面的主窗口之外的其他部分

瀏覽器引擎- 用來查詢及操作渲染引擎的接口

渲染引擎- 用來顯示請求的內容,例如,如果請求內容為html,它負責解析html及css,并將解析后的結果顯示出來

網絡- 用來完成網絡調用,例如http請求,它具有平臺無關的接口,可以在不同平臺上工作

UI 后端- 用來繪制類似組合選擇框及對話框等基本組件,具有不特定于某個平臺的通用接口,底層使用操作系統的用戶接口

JS解釋器- 用來解釋執行JS代碼

數據存儲- 屬于持久層,瀏覽器需要在硬盤中保存類似cookie的各種數據,HTML5定義了web database技術,這是一種輕量級完整的客戶端存儲技術

解析

當瀏覽器獲得了資源以后要進行的第一步工作就是 HTML 解析,,它由幾個步驟組成:編碼、預解析、標記和構建樹。

編碼

HTTP 響應主體的有效負載可以是從HTML文本到圖像數據的任何內容。解析器的第一項工作是找出如何轉制剛剛從服務器接收到的 bit

假設我們正在處理一個HTML文檔,解碼器必須弄清楚文本文檔是如何被轉換成比特(bit)的,以便反轉這個過程。

記住,最終即使是文本也會被計算機翻譯成二進制,如上圖所示,在本例中是 ASCII 編碼—定義二進制值,如“01000100”表示字母“D”。

對于文本存在許多可能的編碼—瀏覽器的工作是找出如何正確地解碼文本。服務器應該通過 Content-Type 提供的信息同時在文本文件頭部使用 Byte Order Mark 告知瀏覽器編碼格式。

如果仍然無法確定編碼,瀏覽器還會自行匹配一種解碼格式來處理數據。有時候,解碼格式也會寫在 標簽中。

最壞的情況是,瀏覽器進行了有根據的猜測,然后開始解析之后發現一個矛盾的 標簽。在這些罕見的情況下,解析器必須重新啟動,丟棄之前解碼的內容。瀏覽器有時必須處理舊的 web內容(使用遺留編碼),許多這樣的系統都支持這一點。

我們現在經常在 HTML中使用的文件格式是 UTF-8,那是因為 UTF-8 能較完整的支持Unicode 字符范圍,同時與 CSS、JavaScript 中常見的節字符具有良好的 ASCII 兼容性。一般瀏覽器默認的解碼格式也是 UTF-8。當解碼出錯的時候,我們會看到屏幕上全部都是亂碼字符。

預解析

在執行腳本時,其他線程會解析文檔的其余部分,找出并加載需要通過網絡加載的其他資源。通過這種方式,資源可以在并行連接上加載,從而提高總體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工作交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的引用。

預解析器不是完整的解析器,如,它不理解 HTML 中的嵌套級別或父/子關系。但是,預解析可以識別特定的 HTML 標簽的名稱和屬性,以及 URL。例如,如果你的 HTML 內容中有一個 ,預解析將注意到src屬性,并將獲取這個圖片的請求加到請求隊列中。

請求圖片的速度越快越好,將等待它從網絡到達的時間降到最低。預解析還會注意到 HTML 中的某些顯式請求,比如 preloadprefetch 指令,并將它們加入等待隊友中進行處理。

標記化(Tokenization)

該算法的輸出結果是 HTML 標記。該算法使用狀態機來表示。每一個狀態接收來自輸入信息流的一個或多個字符,并根據這些字符更新下一個狀態。當前的標記化狀態和樹結構狀態會影響進入下一狀態的決定。這意味著,即使接收的字符相同,對于下一個正確的狀態也會產生不同的結果,具體取決于當前的狀態。該算法相當復雜,無法在此詳述,所以我們通過一個簡單的示例來幫助大家理解其原理。

基本示例 - 將下面的 HTML 代碼標記化:


  
    Hello world
  

初始狀態是數據狀態。遇到字符 < 時,狀態更改為“標記打開狀態”。接收一個 a-z 字符會創建“起始標記”,狀態更改為“標記名稱狀態”。這個狀態會一直保持到接收 > 字符。在此期間接收的每個字符都會附加到新的標記名稱上。在本例中,我們創建的標記是 html 標記。

遇到 > 標記時,會發送當前的標記,狀態改回“數據狀態”。 標記也會進行同樣的處理。目前 html 和 body 標記均已發出。現在我們回到“數據狀態”。接收到 Hello world 中的 H 字符時,將創建并發送字符標記,直到接收 中的 <。我們將為 Hello world 中的每個字符都發送一個字符標記。

現在我們回到“標記打開狀態”。接收下一個輸入字符 / 時,會創建 end tag token 并改為“標記名稱狀態”。我們會再次保持這個狀態,直到接收 >。然后將發送新的標記,并回到“數據狀態”。 輸入也會進行同樣的處理。

構建樹(tree construction)

在創建解析器的同時,也會創建 Document 對象。在樹構建階段,以 Document 為根節點的 DOM 樹也會不斷進行修改,向其中添加各種元素。標記生成器發送的每個節點都會由樹構建器進行處理。規范中定義了每個標記所對應的 DOM 元素,這些元素會在接收到相應的標記時創建。這些元素不僅會添加到 DOM 樹中,還會添加到開放元素的堆棧中。此堆棧用于糾正嵌套錯誤和處理未關閉的標記。其算法也可以用狀態機來描述。這些狀態稱為“插入模式”

在上一步符號化以后,解析器獲得這些標記,然后以合適的方法創建 DOM 對象并將這些符號插入到 DOM 對象中。DOM 對象的數據結構是樹狀的,所以這個過程稱為構造樹(tree construction)。另外,在 IE 的歷史中,大部分時間里沒有使用樹結構。

在創建解析器的同時,也會創建 Document 對象。在樹構建階段,以 Document 為根節點的 DOM 樹也會不斷進行修改,向其中添加各種元素。標記生成器發送的每個節點都會由樹構建器進行處理。

規范中定義了每個標記所對應的 DOM 元素,這些元素會在接收到相應的標記時創建。這些元素不僅會添加到 DOM 樹中,還會添加到開放元素的堆棧中。此堆棧用于糾正嵌套錯誤和處理未關閉的標記。其算法也可以用狀態機來描述。這些狀態稱為“插入模式”。

例如,考慮這個 HTML:

sincerely

The authors

這樣可以確保結果樹中的兩個段落對象是兄弟節點,而忽略第二個打開的標簽則與一個段落對象相對。 HTML表可能是解析器規則試圖確保表具有適當結構的最復雜的表。

盡管存在所有復雜的解析規則,但是一旦創建了 DOM 樹,所有試圖創建正確 HTML 結構的解析規則就不再強制執行了。

使用 JavaScript,網頁可以幾乎以任何方式重新排列 DOM 樹,即使它沒有意義,例如,添加表格單元格作為 標簽的子項,渲染系統負責弄清楚如何處理任何前后不一致標簽。

HTML 解析中的另一個復雜因素是 JavaScript 可以在解析器執行其工作時添加更多要解析的內容。

還可以取消一些事件,例如,如果表單沒有正確填寫,則可以停止表單提交。(提交事件是從

元素觸發的,JavaScript 偵聽器可以檢查表單,如果字段為空或無效,還可以選擇取消事件。)

DOM

HTML語言提供了豐富的特性集,遠遠超出了解析器處理的標記。解析器構建一個結構,其中的元素包含其他元素,以及這些元素最初具有什么狀態(它們的屬性)。結構和狀態的組合足以提供基本渲染和一些交互(例如通過內置控件,如