成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

瀏覽器將標(biāo)簽轉(zhuǎn)成 DOM 的過(guò)程

LancerComet / 2411人閱讀

摘要:在這些罕見的情況下,解析器必須重新啟動(dòng),丟棄之前解碼的內(nèi)容。標(biāo)簽包含解析器必須收集的文本,然后發(fā)送到腳本引擎進(jìn)行評(píng)估。如果文件內(nèi)調(diào)用了,解析器將重新開始解析過(guò)程。事件當(dāng)解析器完成時(shí),它通過(guò)一個(gè)名為的事件宣布完成。

瀏覽器基本的工作流程

想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你!

進(jìn)入主話題之前,先羅列一下瀏覽器的主要構(gòu)成:

用戶界面- 包括地址欄、后退/前進(jìn)按鈕、書簽?zāi)夸浀龋簿褪悄闼吹降某擞脕?lái)顯示你所請(qǐng)求頁(yè)面的主窗口之外的其他部分

瀏覽器引擎- 用來(lái)查詢及操作渲染引擎的接口

渲染引擎- 用來(lái)顯示請(qǐng)求的內(nèi)容,例如,如果請(qǐng)求內(nèi)容為html,它負(fù)責(zé)解析html及css,并將解析后的結(jié)果顯示出來(lái)

網(wǎng)絡(luò)- 用來(lái)完成網(wǎng)絡(luò)調(diào)用,例如http請(qǐng)求,它具有平臺(tái)無(wú)關(guān)的接口,可以在不同平臺(tái)上工作

UI 后端- 用來(lái)繪制類似組合選擇框及對(duì)話框等基本組件,具有不特定于某個(gè)平臺(tái)的通用接口,底層使用操作系統(tǒng)的用戶接口

JS解釋器- 用來(lái)解釋執(zhí)行JS代碼

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

解析

當(dāng)瀏覽器獲得了資源以后要進(jìn)行的第一步工作就是 HTML 解析,,它由幾個(gè)步驟組成:編碼、預(yù)解析、標(biāo)記和構(gòu)建樹。

編碼

HTTP 響應(yīng)主體的有效負(fù)載可以是從HTML文本到圖像數(shù)據(jù)的任何內(nèi)容。解析器的第一項(xiàng)工作是找出如何轉(zhuǎn)制剛剛從服務(wù)器接收到的 bit。

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

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

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

如果仍然無(wú)法確定編碼,瀏覽器還會(huì)自行匹配一種解碼格式來(lái)處理數(shù)據(jù)。有時(shí)候,解碼格式也會(huì)寫在 標(biāo)簽中。

最壞的情況是,瀏覽器進(jìn)行了有根據(jù)的猜測(cè),然后開始解析之后發(fā)現(xiàn)一個(gè)矛盾的 標(biāo)簽。在這些罕見的情況下,解析器必須重新啟動(dòng),丟棄之前解碼的內(nèi)容。瀏覽器有時(shí)必須處理舊的 web內(nèi)容(使用遺留編碼),許多這樣的系統(tǒng)都支持這一點(diǎn)。

我們現(xiàn)在經(jīng)常在 HTML中使用的文件格式是 UTF-8,那是因?yàn)?UTF-8 能較完整的支持Unicode 字符范圍,同時(shí)與 CSS、JavaScript 中常見的節(jié)字符具有良好的 ASCII 兼容性。一般瀏覽器默認(rèn)的解碼格式也是 UTF-8。當(dāng)解碼出錯(cuò)的時(shí)候,我們會(huì)看到屏幕上全部都是亂碼字符。

預(yù)解析

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

預(yù)解析器不是完整的解析器,如,它不理解 HTML 中的嵌套級(jí)別或父/子關(guān)系。但是,預(yù)解析可以識(shí)別特定的 HTML 標(biāo)簽的名稱和屬性,以及 URL。例如,如果你的 HTML 內(nèi)容中有一個(gè) ,預(yù)解析將注意到src屬性,并將獲取這個(gè)圖片的請(qǐng)求加到請(qǐng)求隊(duì)列中。

請(qǐng)求圖片的速度越快越好,將等待它從網(wǎng)絡(luò)到達(dá)的時(shí)間降到最低。預(yù)解析還會(huì)注意到 HTML 中的某些顯式請(qǐng)求,比如 preloadprefetch 指令,并將它們加入等待隊(duì)友中進(jìn)行處理。

標(biāo)記化(Tokenization)

該算法的輸出結(jié)果是 HTML 標(biāo)記。該算法使用狀態(tài)機(jī)來(lái)表示。每一個(gè)狀態(tài)接收來(lái)自輸入信息流的一個(gè)或多個(gè)字符,并根據(jù)這些字符更新下一個(gè)狀態(tài)。當(dāng)前的標(biāo)記化狀態(tài)和樹結(jié)構(gòu)狀態(tài)會(huì)影響進(jìn)入下一狀態(tài)的決定。這意味著,即使接收的字符相同,對(duì)于下一個(gè)正確的狀態(tài)也會(huì)產(chǎn)生不同的結(jié)果,具體取決于當(dāng)前的狀態(tài)。該算法相當(dāng)復(fù)雜,無(wú)法在此詳述,所以我們通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)幫助大家理解其原理。

基本示例 - 將下面的 HTML 代碼標(biāo)記化:


  
    Hello world
  

初始狀態(tài)是數(shù)據(jù)狀態(tài)。遇到字符 < 時(shí),狀態(tài)更改為“標(biāo)記打開狀態(tài)”。接收一個(gè) a-z 字符會(huì)創(chuàng)建“起始標(biāo)記”,狀態(tài)更改為“標(biāo)記名稱狀態(tài)”。這個(gè)狀態(tài)會(huì)一直保持到接收 > 字符。在此期間接收的每個(gè)字符都會(huì)附加到新的標(biāo)記名稱上。在本例中,我們創(chuàng)建的標(biāo)記是 html 標(biāo)記。

遇到 > 標(biāo)記時(shí),會(huì)發(fā)送當(dāng)前的標(biāo)記,狀態(tài)改回“數(shù)據(jù)狀態(tài)”。 標(biāo)記也會(huì)進(jìn)行同樣的處理。目前 html 和 body 標(biāo)記均已發(fā)出?,F(xiàn)在我們回到“數(shù)據(jù)狀態(tài)”。接收到 Hello world 中的 H 字符時(shí),將創(chuàng)建并發(fā)送字符標(biāo)記,直到接收 中的 <。我們將為 Hello world 中的每個(gè)字符都發(fā)送一個(gè)字符標(biāo)記。

現(xiàn)在我們回到“標(biāo)記打開狀態(tài)”。接收下一個(gè)輸入字符 / 時(shí),會(huì)創(chuàng)建 end tag token 并改為“標(biāo)記名稱狀態(tài)”。我們會(huì)再次保持這個(gè)狀態(tài),直到接收 >。然后將發(fā)送新的標(biāo)記,并回到“數(shù)據(jù)狀態(tài)”。 輸入也會(huì)進(jìn)行同樣的處理。

構(gòu)建樹(tree construction)

在創(chuàng)建解析器的同時(shí),也會(huì)創(chuàng)建 Document 對(duì)象。在樹構(gòu)建階段,以 Document 為根節(jié)點(diǎn)的 DOM 樹也會(huì)不斷進(jìn)行修改,向其中添加各種元素。標(biāo)記生成器發(fā)送的每個(gè)節(jié)點(diǎn)都會(huì)由樹構(gòu)建器進(jìn)行處理。規(guī)范中定義了每個(gè)標(biāo)記所對(duì)應(yīng)的 DOM 元素,這些元素會(huì)在接收到相應(yīng)的標(biāo)記時(shí)創(chuàng)建。這些元素不僅會(huì)添加到 DOM 樹中,還會(huì)添加到開放元素的堆棧中。此堆棧用于糾正嵌套錯(cuò)誤和處理未關(guān)閉的標(biāo)記。其算法也可以用狀態(tài)機(jī)來(lái)描述。這些狀態(tài)稱為“插入模式”

在上一步符號(hào)化以后,解析器獲得這些標(biāo)記,然后以合適的方法創(chuàng)建 DOM 對(duì)象并將這些符號(hào)插入到 DOM 對(duì)象中。DOM 對(duì)象的數(shù)據(jù)結(jié)構(gòu)是樹狀的,所以這個(gè)過(guò)程稱為構(gòu)造樹(tree construction)。另外,在 IE 的歷史中,大部分時(shí)間里沒(méi)有使用樹結(jié)構(gòu)。

在創(chuàng)建解析器的同時(shí),也會(huì)創(chuàng)建 Document 對(duì)象。在樹構(gòu)建階段,以 Document 為根節(jié)點(diǎn)的 DOM 樹也會(huì)不斷進(jìn)行修改,向其中添加各種元素。標(biāo)記生成器發(fā)送的每個(gè)節(jié)點(diǎn)都會(huì)由樹構(gòu)建器進(jìn)行處理。

規(guī)范中定義了每個(gè)標(biāo)記所對(duì)應(yīng)的 DOM 元素,這些元素會(huì)在接收到相應(yīng)的標(biāo)記時(shí)創(chuàng)建。這些元素不僅會(huì)添加到 DOM 樹中,還會(huì)添加到開放元素的堆棧中。此堆棧用于糾正嵌套錯(cuò)誤和處理未關(guān)閉的標(biāo)記。其算法也可以用狀態(tài)機(jī)來(lái)描述。這些狀態(tài)稱為“插入模式”。

例如,考慮這個(gè) HTML:

sincerely

The authors

這樣可以確保結(jié)果樹中的兩個(gè)段落對(duì)象是兄弟節(jié)點(diǎn),而忽略第二個(gè)打開的標(biāo)簽則與一個(gè)段落對(duì)象相對(duì)。 HTML表可能是解析器規(guī)則試圖確保表具有適當(dāng)結(jié)構(gòu)的最復(fù)雜的表。

盡管存在所有復(fù)雜的解析規(guī)則,但是一旦創(chuàng)建了 DOM 樹,所有試圖創(chuàng)建正確 HTML 結(jié)構(gòu)的解析規(guī)則就不再?gòu)?qiáng)制執(zhí)行了。

使用 JavaScript,網(wǎng)頁(yè)可以幾乎以任何方式重新排列 DOM 樹,即使它沒(méi)有意義,例如,添加表格單元格作為 標(biāo)簽的子項(xiàng),渲染系統(tǒng)負(fù)責(zé)弄清楚如何處理任何前后不一致標(biāo)簽。

HTML 解析中的另一個(gè)復(fù)雜因素是 JavaScript 可以在解析器執(zhí)行其工作時(shí)添加更多要解析的內(nèi)容。

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

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

DOM

HTML語(yǔ)言提供了豐富的特性集,遠(yuǎn)遠(yuǎn)超出了解析器處理的標(biāo)記。解析器構(gòu)建一個(gè)結(jié)構(gòu),其中的元素包含其他元素,以及這些元素最初具有什么狀態(tài)(它們的屬性)。結(jié)構(gòu)和狀態(tài)的組合足以提供基本渲染和一些交互(例如通過(guò)內(nèi)置控件,如