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

資訊專欄INFORMATION COLUMN

瀏覽器是如何工作的?(How browser work?)

vincent_xyb / 2975人閱讀

摘要:解析器的工作通常分為兩個內(nèi)容詞法分析器有時稱為標(biāo)記生成器負(fù)責(zé)把輸入分解為很多符號,解析器負(fù)責(zé)根據(jù)該語言的語法規(guī)則來分析文檔結(jié)構(gòu),從而構(gòu)建解析樹。解析器通常會向詞法分析器詢問是否有新的符號,并且試圖通過一條語法規(guī)則的來進(jìn)行匹配。

瀏覽器是如何工作的(How browser work)

1. 介紹

1.1 本文涉及到的瀏覽器

1.2 瀏覽器的主要功能

1.3 瀏覽器的主要結(jié)構(gòu)

1.4 組件之前的通信

2. 渲染引擎

2.1 渲染引擎

2.2 主要的流程

2.3 流程示例

2.4 解析以及DOM樹的結(jié)構(gòu)

2.5 渲染樹(Render tree)的結(jié)構(gòu)

2.6 布局

2.7 繪制(Painting)

2.8 動態(tài)改變

2.9 渲染引擎的線程

2.10 css2 虛擬模型

2.11 資源

1. 介紹

瀏覽器可謂是使用最廣泛的軟件. 這篇文章我將要解釋瀏覽器在底層是如何工作的. 我們將會了解當(dāng)你在瀏覽器地址欄里輸入"google.com"直到頁面呈現(xiàn)出來這一過程都發(fā)生了什么。

1.1 本文涉及到的瀏覽器

目前市面上主要有5款瀏覽器: Internet Explorer, Firefox, Safari, Chrome 以及 Opera。
我將使用開源的瀏覽器中進(jìn)行舉例,包含F(xiàn)irefox, Chrome 以及 部分開源的Fafari。
根據(jù)W3C browser statistics, 當(dāng)前時間是2009年10月,使用Firefox, Safari 以及 Chrome 的比例占據(jù)將近60%。
所以目前開源瀏覽器占據(jù)的瀏覽器市場很大的份額。

1.2 瀏覽器的主要功能

瀏覽器的主要功能是把你從服務(wù)器請求到的網(wǎng)絡(luò)資源呈現(xiàn)在瀏覽器窗口上。資源通常包含了HTML,PDF, 圖片等等。資源通常是由用戶指定的URI(Unifor resource Identifier 統(tǒng)一資源定位符)來定位的。稍后的章節(jié)會介紹。

瀏覽器解釋和呈現(xiàn)HTML文件的方式是通過HTML和CSS規(guī)范來實現(xiàn)的。 這些規(guī)范是由W3C組織進(jìn)行維護(hù)的,該組織是互聯(lián)網(wǎng)的標(biāo)準(zhǔn)制定者。長久以來各個瀏覽器廠商只實現(xiàn)了一部分規(guī)范,并且開發(fā)自己的擴(kuò)展程序。這導(dǎo)致了在不同的瀏覽器當(dāng)中很嚴(yán)重的兼容性問題。到目前為止,大部分的瀏覽器都大多實現(xiàn)了規(guī)范。
不同的瀏覽器UI有很多相同的部分:

輸入URI的地址欄

前進(jìn)和后退按鈕

書簽操作

操作當(dāng)前加載文檔的刷新和停止按鈕

返回主頁的主頁按鈕

但是比較奇怪的是, 瀏覽器的UI并沒有一個通用的規(guī)范,它只是不同的瀏覽器廠商從長期的使用習(xí)慣中積累的經(jīng)驗。HTML5規(guī)范并沒有規(guī)定瀏覽器的UI必須包含哪些元素,只是列出了一些通用的元素。地址欄、狀態(tài)欄、工具欄以及各個瀏覽器指定的特定,例如Firefox的下載管理。更多參見用戶界面章節(jié)。

1.3 瀏覽器的主要結(jié)構(gòu)

瀏覽器的主要組成部分:

用戶界面(The user interface) - 包含地址欄、前進(jìn)/后退按鈕、書簽等等。除了主要的窗口之外你所看到的就是請求的頁面。

瀏覽器引擎 - 查詢和操作渲染引擎的入口。

渲染引擎 - 負(fù)責(zé)呈現(xiàn)請求內(nèi)容。例如請求內(nèi)容是HTML, 渲染引擎負(fù)責(zé)解析HTML以及CSS,并且渲染解析后的內(nèi)容到屏幕上。

網(wǎng)絡(luò)鏈接 - 處理形如HTTP的網(wǎng)絡(luò)請求。它有針對不同平臺的實現(xiàn)接口。

用戶界面的后臺處理程序(UI Backend) - 用于繪制類似于 bombo 盒子的小部件以及一些窗口。它拋出了各個平臺通用的接口。它的底層是
使用了操作系統(tǒng)的用戶界面方法。

Javascript 解釋器。 用于解析和執(zhí)行Javascrip代碼。

數(shù)據(jù)存儲。 這是一個持久層。瀏覽器需要在硬盤上保存各種各樣的數(shù)據(jù),比如coocies。HTNL5規(guī)范定義了"web database",針對瀏覽器的完整的數(shù)據(jù)庫(盡管比較輕量)

Figure 1: Browser main components.

值得注意的是,Chrome不像其他的瀏覽器, 它給每一個tab分配一個渲染引擎的實例,每一個tab都是一個獨立的進(jìn)程。

1.4 組件間的通信

Firefox 和 Chrome 都獨自開發(fā)了一套特別的通信機(jī)制。

2. 渲染引擎

渲染引擎的職責(zé)就是進(jìn)行渲染, 也就是負(fù)責(zé)把請求到的內(nèi)容呈現(xiàn)在瀏覽器屏幕上。

在默認(rèn)情況下,渲染引擎能夠展示HTML,XML以及image文檔。也能通過插件來展示其他類型的文檔。例如通過PDF視圖插件可以展示PDF。我們將會在特定的章節(jié)討論插件和擴(kuò)展程序。本章節(jié)主要著重于主要的情況-如何展示由css格式化的HTML和images。

2.1 渲染引擎

我們參考的Firefox,Chrome,Safari瀏覽器都是基于兩個渲染引擎建立的。 Firefox 使用 Gecko, 一個Mozilla自己開發(fā)的引擎。Safari 和 Chrome 都是使用的Webkit引擎。Webkit 引擎最開始是用于linux平臺的開源引擎。后續(xù)被修改用于支持Apple的Mac以及 Windows系統(tǒng)。 詳情移步http://webkit.org/

2.2 主要渲染流程

渲染引擎將會從網(wǎng)絡(luò)層請求到內(nèi)容開始進(jìn)行工作。這通常的大小在8k以內(nèi)。

在這之后,以下就是渲染引擎基本的流程:

Figure 2: Render engine basic flow.  

解析HTML, 生成DOM tree -> 渲染render tree結(jié)構(gòu) -> 組織render tree 的布局 -> 在窗口繪制 render tree

渲染引擎會解析HTML文檔,把HTML文檔解析為“內(nèi)容樹(content tree)”, 并把HTML標(biāo)簽轉(zhuǎn)換為樹中的DOM節(jié)點。渲染引擎還要解析樣式文件,包含外鏈樣式文件以及內(nèi)聯(lián)樣式元素。樣式信息和HTML當(dāng)中可視化的指令將會用于創(chuàng)建另外一個樹 - 渲染樹 (render tree)。

渲染樹包含了具有顏色以及尺寸等可視化屬性的矩形盒子集合。這些矩形盒子都是按照在屏幕上的顯示順序排序的。

在構(gòu)造晚渲染樹之后,將會經(jīng)過“l(fā)ayout”過程。意思就是給每一個節(jié)點設(shè)置在屏幕上顯示的確切坐標(biāo)位置。下一個階段是繪制(painting) - 渲染樹將會通過UI的后臺處理層,每一個節(jié)點都將會被繪制。

了解渲染的過程是一個循序漸進(jìn)的過程很重要。為了達(dá)到更好的用戶體驗,渲染引擎將會盡可能快的把內(nèi)容展示在屏幕上。它并不會等到所有的HTML都解析完之后才去構(gòu)建和布局渲染樹。當(dāng)請求到一部分內(nèi)容的時候,引擎將會解析和渲染這一部分內(nèi)容,同時程序也將繼續(xù)解析從網(wǎng)絡(luò)中請求到的余下的內(nèi)容。

2.3 渲染流程示例

Figure 3: Webkit main flow

Figure 4: Mozilla"s Gecko rendering engine main flow

從圖3 和圖4 中可以看到盡管Webkit 和 Gecko 使用了稍微不同的術(shù)語,但是流程是基本相同的。
Gecko 把格式化的元素形象的稱為:Frame tree(結(jié)構(gòu)樹)。每一個元素都是一個框架。Webkit 使用術(shù)語:Render tree, 它由Render Object 組成。Webkit把設(shè)置元素的位置稱為layout,而 Gecko稱為Reflow。 Webkit 把連接DOM節(jié)點和視覺信息生成渲染樹稱為Attachment。另外一個較小的非語義上的差別是Gecko在HTML與DOM樹之間多了額外的一層。叫做content sink, 它是創(chuàng)建DOM元素的工廠。我們將會逐個了解流程的每一部分。

通常的解析

既然解析在渲染引擎內(nèi)是一個非常重要的過程,我們將會深入的了解它。
文檔解析,亦即把它轉(zhuǎn)換為一種代碼可以理解和使用的結(jié)構(gòu)。解析的結(jié)果通常是一個表示文檔結(jié)構(gòu)的節(jié)點樹。它被稱為解析樹或者語法樹
例如:2 + 3 - 1 的表達(dá)式解析結(jié)果為

Figure 5: 運(yùn)算表達(dá)式的樹節(jié)點

文法

解析是基于創(chuàng)建文檔語言所遵循的語法規(guī)則。每一個你能夠解析的格式,都有一個由詞法和語法規(guī)則組成的確切的文法。它被稱為context free grammar(上下文無關(guān)的語法)。人類語言不是這樣的語言,也就是說沒法用常規(guī)的解析技術(shù)來進(jìn)行解析。

解析器 - 詞法組合

解析可以被分為兩個步驟 - 詞法分析 以及 語法分析。
詞法分析是把輸入的內(nèi)容分解為很多符號的一個過程。這些符號是構(gòu)成語言的詞匯(構(gòu)建語言有效的塊集合)。在人類的語言中,它就是某種語言在字典中的所有單詞所組成的。
語法分析就是語言語法規(guī)則的應(yīng)用。
解析器的工作通常分為兩個內(nèi)容:詞法分析器(有時稱為 標(biāo)記生成器)負(fù)責(zé)把輸入分解為很多符號,解析器負(fù)責(zé)根據(jù)該語言的語法規(guī)則來分析文檔結(jié)構(gòu),從而構(gòu)建解析樹。詞法分析器知道如何區(qū)分和解釋特殊的字符,例如空格和換行符。

Figure 6: from source document to parse trees

解析的過程是迭代式的。解析器通常會向詞法分析器詢問是否有新的符號,并且試圖通過一條語法規(guī)則的來進(jìn)行匹配。如果符合某條語法規(guī)則,該符號對應(yīng)的節(jié)點將會被添加到解析樹,緊接著解析器會詢問另外一個符號就行解析。
如果沒有規(guī)則匹配,解析器會在內(nèi)部存儲這個符號,并繼續(xù)詢問下一個符號直到某條規(guī)則匹配所有的內(nèi)部存儲的符號。如果沒有找到對應(yīng)的規(guī)則,解析器就回拋出一個異常。這意味著這個文檔無效,并且包含語法錯誤。

翻譯

通常解析樹并不是最終的結(jié)果。解析結(jié)果通常被翻譯-把文檔翻譯為另外一種格式。一個例子就是匯編。編譯器會把源碼編譯為機(jī)器碼,首先會把源碼解析為解析樹,然后再把解析樹翻譯為機(jī)器碼文檔。

Figure 7: compilation flow

解析實例

在圖5中,我們從一個數(shù)學(xué)表達(dá)式中創(chuàng)建了一個解析樹。 讓我們來定義一個簡單的數(shù)學(xué)語言來了解解析過程。

詞匯: 我們的語言包含整數(shù),加法符號,減法符號

語法:

1. 構(gòu)成語法的元素包含表達(dá)式,運(yùn)算項,運(yùn)算符。  
2. 我們的語言能夠包含任意數(shù)量的表達(dá)式。  
3. 一個表達(dá)式定義為: 一個運(yùn)算項 跟著一個 操作符,再跟著另外一個運(yùn)算項。  
4. 操作符為加號或者減號  
5. 運(yùn)算項為一個整數(shù)或者一個表達(dá)式。

分析下:"2 + 3 - 1"。
根據(jù)上面第5條規(guī)則,第一個匹配規(guī)則的子串是"2"。第二個匹配的的結(jié)果是"2 + 3",它對應(yīng)第二條規(guī)則。下一個匹配的結(jié)果已經(jīng)到了該輸入項的結(jié)尾。我們已經(jīng)知道了形如?2 + 3?表示一個完整項,那么 "2 + 3 + 1"就是一個表達(dá)式。"2 + +" 是一個無效的輸入,因為沒有匹配任何規(guī)則。

正式的定義詞匯和語法

詞匯通常都通過常規(guī)的表達(dá)式來表示。
例如我們將會像下面這樣來定義我們的語言:
INTER :0|1-9*
PLUS : +
MINUS : -
如你所見,整數(shù)是通過常規(guī)的表達(dá)式來表達(dá)的。
語法是遵循BNF(Backus Naur form).html)來定義的。我們的語言將會做如下的定義:
expression := term operation tem
operation := PLUS | MINUS
term := INTEGER | expression

我們之前說過,如果程序的語法是一個上下文無關(guān)的語法,就可以使用通常的解析器進(jìn)行解析。上下文無關(guān)的語法,最直觀的定義就是可以完全使用BNF來表示。可以參見http://en.wikipedia.org/wiki/Context-free_grammar

解析器類型

解析器有兩種類型: 自上而下 和 自下而上 的解析器。 自上而下的解析器是從語法層級比較高的地方著手進(jìn)行匹配解析。自下而上的解析方式是從輸入開始,逐級向上翻譯為對應(yīng)的語法規(guī)則,直到語法層級較高的規(guī)則為止。

讓我們結(jié)合實例來看看這兩種解析方式:

自上而下的解析將會從層級比較高的規(guī)則開始: 它將把 2 + 3 定義為一個表達(dá)式。然后再把 2 + 3 -1 定義為一個表達(dá)式。
自下而上的解析將會掃描整個輸入的字符串,如果有符合的規(guī)則, 則會根據(jù)規(guī)則替換匹配項,直到替換玩整個輸入。匹配的表達(dá)式將會存儲在解析器棧里。

Stack Input
2 + 3 - 1
term + 3 - 1
term operation 3 - 1
expression - 1
expression operation 1
expression

自下而上的解析方式又稱之為移動減少解析器(shift reduce parser),因為輸入是從左向右移動的,并且根據(jù)規(guī)則匹配主鍵減少。

自動生成解析器

可以通過工具生成解析器,被稱之為解析器生成器。 你只需要提供語言的詞匯以及語法規(guī)則,它就能夠生成一個可用的解析器。創(chuàng)建一個解析器徐傲對解析有深入的理解。不太容易手動創(chuàng)建一個解析器,所有解析器生成器會比較有用。

Webkit 使用兩個比較出名的解析器生成器: Flex 用于創(chuàng)建詞法分析器, Bison用于創(chuàng)建解析器(你可以使用Lex 和 Yacc來運(yùn)行)。Flex的輸入是包含通常的表達(dá)式定義的一個文件。Bison 的輸入是BNF格式的語法規(guī)則。

HTML 解析器

HTML解析器的職責(zé)是把HTML標(biāo)記轉(zhuǎn)換為解析樹。

HTML 語法定義

HTML的詞匯和語法在w3c創(chuàng)建的規(guī)范里定義。

非上下文無關(guān)的程序語言

在解析一節(jié)的介紹里,我們知道程序語法可以通過BNF格式進(jìn)行定義。
但是不幸的是,所有常規(guī)的解析器都不適用于HTML。HTML不能夠被輕易的定義為解析器需要的上下文無關(guān)的程序語法。
有一個定義HTML的通用格式-DTD(Document Type Definition), 不過并不是上下文無關(guān)的語法。
一眼看上去, HTML與XML非常的接近。 有很多的XML解析器。有一個HTML的XML變體-XXHTML。這二者有什么不用呢?
不同之處在于HTML的目的在于非嚴(yán)謹(jǐn)?shù)模试S忽略你某些標(biāo)簽,并隱式的添加上,例如有時候允許忽略開始或者結(jié)束標(biāo)簽。不同于XML語法的嚴(yán)格和硬性要求,HTML整體上都是比較寬泛的。
一方面這也是HTML如此瀏覽的一個原因,允許你犯錯,讓web開發(fā)更容易。另一方面,它導(dǎo)致很難定義一個語法格式。總結(jié)起來說, HTML比較難解析,由于并不是一個上下文無關(guān)的編程語法,它不能夠被普通的解析器解析, 也不能被XML解析器解析。

HTML DTD

HTML是通過DTD來定義的。 這個格式用于定義SGML(Standard Generalized Markup Language)語言。 它定義了所有允許的元素,屬性以及層級。正如我們之前所說的, HTML DTD 不能形成上下文無關(guān)的語言。
DTD有一些變動,嚴(yán)格模式嚴(yán)格符合規(guī)范,其他的模式支持歷史版本的瀏覽器。 目的也是為了兼容老版本的瀏覽器。 最新的嚴(yán)格DTD地址:http://www.w3.org/TR/html4/strict.dtd

DOM

解析樹是由DOM元素以及屬性節(jié)點組成的。 DOM是Document Objectd Model 的簡稱。 它是HTML文檔的對象形式以及其他外部語言(形如Javascript)的接口。樹的根節(jié)點是 Document 對象。

DOM與標(biāo)簽之前有著一對一的對應(yīng)關(guān)系。 例如:

    
        
            

Hello World

將會被翻譯為以下的DOM樹:

Figure 8: DOM tree of the example markup  

跟HTML一樣, DOM也是被w3c組織定義和管理的。詳見http://www.w3.org/DOM/DOMTR。 它是操作文檔的通用規(guī)范。 一個特定的模塊描述了HTML特定的元素。 HTML定義可以參見http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html。

當(dāng)我說樹包含了DOM節(jié)點, 意即樹是由實現(xiàn)了DOM接口的元素構(gòu)建的。 不同的瀏覽器使用了具體的實現(xiàn),這些實現(xiàn)包含了瀏覽器內(nèi)部使用的其他屬性。

解析算法

在前幾節(jié)中,我們知道, HTML不能夠通過自上而下或者自下而上的解析器解析。
原因如下:

1. 語言的非嚴(yán)謹(jǐn)性。  
2. 瀏覽器具有傳統(tǒng)的容錯機(jī)制,用于支持很好的辨別無效的HTML。  
3. 解析進(jìn)程的反復(fù)迭代機(jī)制。 在解析的過程中,解析源通常都不會被改變, 但是在HTML中, script標(biāo)簽包含了document.write, 可以添    加額外的元素,所以解析過程中修改了原始輸入。  

由于不能夠使用通常的解析器就行解析, 瀏覽器為解析HTML創(chuàng)建了定制的解析器。
解析算法在HTML5規(guī)范中有詳細(xì)的描述。 算法由兩步構(gòu)成: 符號化 和 構(gòu)建樹。
符號化即詞法分析,把輸入解析為一組符號。 HTML的符號包括開始標(biāo)簽, 結(jié)束標(biāo)簽, 屬性名和屬性值。
標(biāo)記生成器識別不同的標(biāo)記, 并把它傳遞給樹構(gòu)造器,緊接著識別下一個標(biāo)記, 周而復(fù)始, 直到結(jié)束。

Figure 6: HTML parsing flow (taken from HTML5 spec)  

符號化的算法

算法的輸出結(jié)果是一個HTML的標(biāo)簽。 算法被表示為狀態(tài)機(jī)。 每一個狀態(tài)消耗一個或者多個輸入流的字符,然后根據(jù)選中的字符跟更新下一個狀態(tài)。 當(dāng)前的執(zhí)行會被符號化的狀態(tài)和構(gòu)建樹的狀態(tài)所影響。 這意味著, 相同的符號處理,將會產(chǎn)生不同的結(jié)果,根據(jù)當(dāng)前的狀體來糾正下一個狀態(tài)。這個算法太復(fù)雜了, 因此不能完整的呈現(xiàn)出來。 所有我們通過一個簡單的實例來幫助我們理解這個原則。

基礎(chǔ)實例: 符號化以下的HTML:

    
        
            Hello world
        
    

初始狀態(tài)是"Data state"。當(dāng)遇到"<"符號的時候 ,狀態(tài)被變更為"Tag open state"。在處理"a-z"之間的字符時會創(chuàng)建"Start tag token",狀態(tài)被變更為"Tag name state"。狀態(tài)會一直保持,直到遇到">"字符。每一個字符都會被添加到新的標(biāo)簽名里。在我們的事例里創(chuàng)建的是一個"html"標(biāo)簽。

當(dāng)處理到">"符號的時候,當(dāng)前的標(biāo)簽就回被發(fā)送出去,同時狀態(tài)會變更回"Data state"。""標(biāo)簽也以同樣的方式進(jìn)行處理。到目前為止,"html"和"body"標(biāo)簽都被觸發(fā)。我們現(xiàn)在回到了"Data state"。

處理"Hello world"中的"H"字符會創(chuàng)建和出發(fā)一個字符標(biāo)簽,直到遇到""的"<"符號為止。我們會為"Hello world"的每一個字符都觸發(fā)一個字符標(biāo)簽。

現(xiàn)在我們回到"Tag open state"。處理"/"會創(chuàng)建一個"end tag token",并且狀態(tài)變更為"Tag name state"。我們依然保留當(dāng)前狀態(tài)直到遇到">"為止。之后新的標(biāo)簽就回被出發(fā),狀態(tài)返回"Data state"。""的處理方式雷同。

Figure 9: Tokenizing the example input

樹結(jié)構(gòu)算法

當(dāng)解析器被創(chuàng)建的時候,文檔對象也會被創(chuàng)建。在構(gòu)建樹結(jié)構(gòu)的過程中,文檔的DOM樹將會被修改,相應(yīng)的元素將會被添加進(jìn)去。標(biāo)記生成器創(chuàng)建的每一個節(jié)點都會被樹構(gòu)造器處理。規(guī)范中定義的每一個DOM元素關(guān)聯(lián)的標(biāo)記都會被創(chuàng)建。除了把元素添加到DOM樹之外,還會被添加到"open elements"棧中。這個棧被用于糾正不匹配的嵌套以及處理未關(guān)閉的標(biāo)簽。這個算法過程也被描述為一個狀態(tài)機(jī)。狀態(tài)被稱為"insertion modes"。

讓我們看看事例中構(gòu)造樹的過程:

    
        
            Hello world
        
    

樹構(gòu)造階段接收的輸入是從字符化階段傳入的字符序列。第一個模式是"initial mode"。當(dāng)接收到html標(biāo)簽的時候,會移動到"before html"模式,同時再對標(biāo)簽進(jìn)行處理。此時會創(chuàng)建一個HTMLHtmlElement元素,這個元素會被添加到文檔對象的根節(jié)點。

之后狀態(tài)將會變?yōu)?before head"。我們會接收到body標(biāo)簽,此時將會隱式的創(chuàng)建一個HTMLHeadElementut元素并添加到DOM樹里,盡管示例中并沒有head標(biāo)簽。

緊接著移動到"in head",然后是"after head"。body標(biāo)簽會被再加工,一個HTMLBodyElement將會被創(chuàng)建和添加到DOM樹, 模式會移動到"in body"。

接下來會接收到"Hello world"字符串。處理第一個字符的時候會創(chuàng)建一個"Text"節(jié)點,其他的字符會被添加到這個節(jié)點中。

當(dāng)接收到body結(jié)束標(biāo)簽的時候會移動到"after body"模式。此時我們會接收到html結(jié)束標(biāo)簽,會移動到"after after body"模式。接收到文件結(jié)束標(biāo)簽的時候?qū)Y(jié)束解析。

Figure 10: tree construction of example html

解析之后的動作

在這一步瀏覽器將會把文檔標(biāo)記為可交互的,同時開始解析在“defferred”模式下的scripts文件(在文檔解析完成之后將會被執(zhí)行)。文檔的狀態(tài)將會被修改為“complete”,同時觸發(fā)一個“l(fā)oad”事件。

你可以在HTML5規(guī)范里查看標(biāo)記化以及構(gòu)建樹的完整算法。https://www.w3.org/TR/html5/syntax.html

瀏覽器的容錯

在HTML頁面里你永遠(yuǎn)不會收到一個“語法無效”的錯誤。瀏覽器會處理無效的內(nèi)容。

以下面的HTML為例:

    
        
        
        

Really lousy HTML

我已經(jīng)違反了很多規(guī)則(“mytag”不是標(biāo)準(zhǔn)的標(biāo)簽,“p”和“div”標(biāo)簽的錯誤嵌套等等),但是瀏覽器仍然會把內(nèi)容正確的展示出來,并不會報錯。所以有很多的解析代碼來修復(fù)了HTML開發(fā)者的錯誤。

瀏覽器中的錯誤處理始終是一致的,但是讓人比較驚訝的是它并不是當(dāng)前HTML規(guī)范的一部分。它就像書簽和前進(jìn)后退按鈕一樣,只是多年以來在瀏覽器中開發(fā)出來的某個東西。 在很多站點中都已知很多無效的HTML結(jié)構(gòu),瀏覽器會試著已一致的方式修復(fù)它們,以順應(yīng)其他瀏覽器。

HTML5規(guī)范針對這些要求做了一些定義。Webkit在HTML解析類開始的注釋中做了很好的描述:

The parser parses tokenized input into the document, building up the document tree. If the document is well-formed, parsing it is straightforward.

Unfortunately, we have to handle many HTML documents that are not well-formed, so the parser has to be tolerant about errors.

We have to take care of at least the following error conditions:

1. The element being added is explicitly forbidden inside some outer tag.
In this case we should close all tags up to the one, which forbids the element, and add it afterwards.

2. We are not allowed to add the element directly. 
It could be that the person writing the document forgot some tag in between (or that the tag in between is optional).
This could be the case with the following tags: HTML HEAD BODY TBODY TR TD LI (did I forget any?).

3. We want to add a block element inside to an inline element. Close all inline elements up to the next higher block element.

4. If this doesn"t help, close elements until we are allowed to add the element or ignore the tag.

讓我們看看Webkit的容錯示例:


instead of

某些站點使用
代替
。為了兼容IE和Firefox, Webkit 使用

代碼:

if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
    reportError(MalformedBRError);
    t->beginTag = true;
}

注意: 錯誤處理是在內(nèi)容,并不會呈現(xiàn)給用戶。

錯亂的table

錯亂偏離的table是指在另外一個table里但是卻不在table cell里的table。

就像下面的例子:

inner table
outer table

Webkit 就會把結(jié)構(gòu)修改為兩個子table

outer table
inner table

代碼:

if (m_inStrayTableContent && localName == tableTag)
    popBlock(tableTag);

Webkit 使用棧來管理當(dāng)前元素內(nèi)容,它會彈出內(nèi)部table,再入棧到外部table的棧中。table至此就相鄰了。

嵌套的表單元素

以防用戶在form 中放置另外一個form, 第二個form將會被忽略。

if (!m_currentFormElement) {
    m_currentFormElement = new HTMLFormElement(formTag,    m_document);
}

過深的標(biāo)簽層級

注釋不言而喻。

www.liceo.edu.mx is an example of a site that achieves a level of nesting of about 1500 tags, all from a bunch of s.
We will only allow at most 20 nested tags of the same type before just ignoring them all together.

代碼:

bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{

unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
        i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
    curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}

html和body結(jié)束標(biāo)簽的錯放

看注釋:

Support for really broken html.
We never close the body tag, since some stupid web pages close it before the actual end of the doc.
Let"s rely on the end() call to close things.

if (t->tagName == htmlTag || t->tagName == bodyTag )
    return;

所以web開發(fā)者需要注意: 除非你想呈現(xiàn)一個Webkit容錯的示例代碼,否則請編寫完整的HTML標(biāo)簽。

CSS解析

待續(xù)...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/54054.html

相關(guān)文章

  • 程序員練級攻略(2018):前端基礎(chǔ)和底層原理

    摘要:下面我們從前端基礎(chǔ)和底層原理開始講起。對于和這三個對應(yīng)于矢量圖位圖和圖的渲染來說,給前端開發(fā)帶來了重武器,很多小游戲也因此蓬勃發(fā)展。這篇文章受眾之大,后來被人重新整理并發(fā)布為,其中還包括中文版。 showImg(https://segmentfault.com/img/bVbjM5r?w=1142&h=640); 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 這...

    widuu 評論0 收藏0
  • 覽器如何工作?(How browser work?)

    摘要:解析器的工作通常分為兩個內(nèi)容詞法分析器有時稱為標(biāo)記生成器負(fù)責(zé)把輸入分解為很多符號,解析器負(fù)責(zé)根據(jù)該語言的語法規(guī)則來分析文檔結(jié)構(gòu),從而構(gòu)建解析樹。解析器通常會向詞法分析器詢問是否有新的符號,并且試圖通過一條語法規(guī)則的來進(jìn)行匹配。 瀏覽器是如何工作的(How browser work) 1. 介紹 1.1 本文涉及到的瀏覽器 1.2 瀏覽器的主要功能 1.3 瀏覽器的主要結(jié)構(gòu) 1.4...

    miguel.jiang 評論0 收藏0
  • 覽器如何工作?(How browser work?)

    摘要:解析器的工作通常分為兩個內(nèi)容詞法分析器有時稱為標(biāo)記生成器負(fù)責(zé)把輸入分解為很多符號,解析器負(fù)責(zé)根據(jù)該語言的語法規(guī)則來分析文檔結(jié)構(gòu),從而構(gòu)建解析樹。解析器通常會向詞法分析器詢問是否有新的符號,并且試圖通過一條語法規(guī)則的來進(jìn)行匹配。 瀏覽器是如何工作的(How browser work) 1. 介紹 1.1 本文涉及到的瀏覽器 1.2 瀏覽器的主要功能 1.3 瀏覽器的主要結(jié)構(gòu) 1.4...

    YFan 評論0 收藏0
  • 百度圖片爬蟲(python語言)

    摘要:好的,我也不想多說,爬蟲的代碼我會分享到去轉(zhuǎn)盤網(wǎng),想下載本爬蟲代碼的孩子請點我下載,如果沒有下載到,請點擊這個鏈接。 上一篇我寫了如何爬取百度網(wǎng)盤的爬蟲,在這里還是重溫一下,把鏈接附上: http://www.cnblogs.com/huangx... 這一篇我想寫寫如何爬取百度圖片的爬蟲,這個爬蟲也是:搜搜gif(在線制作功能點我) 的爬蟲代碼,其實爬蟲整體框架還是差不多的,但就是會...

    Ethan815 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<