瀏覽器執行原理
一、瀏覽器簡介
瀏覽器是指可以顯示網頁伺服器或者檔案系統的HTML檔案(標準通用標記語言的一個應用)內容,並讓使用者與這些檔案互動的一種軟體。
瀏覽器的主要功能就是向伺服器發出請求,在瀏覽器視窗中展示您選擇的網路資源。這裡所說的資源一般是指 HTML 文件,也可以是 PDF、 圖片或其他的型別。 資源的位置由使用者使用URI(統一資源標符)指定。多年以來,各瀏覽器都沒有完全遵從這些規範,同時還在開發自己獨有的擴充套件程式,這給網路開發人員帶來了嚴重的相容性問題。 如今,大多數的瀏覽器都是或多或少地遵從規範。
HTML和CSS規範中規定了瀏覽器解釋html文件的方式,由W3C組織對這些規範進行維護,W3C是負責制定web標準的組織。
這些年來,瀏覽器廠商紛紛開發自己的擴充套件,對規範的遵循並不完善,這為web開發者帶來了嚴重的相容性問題。
但是,瀏覽器的使用者介面則差不多,常見的使用者介面元素包括:
- 用來輸入URI的位址列
- 前進、後退按鈕
- 書籤選項
- 用於重新整理及暫停當前載入文件的重新整理、暫停按鈕
- 用於到達主頁的主頁按鈕
目前使用的主流瀏覽器有五個:Internet Explorer、 Firefox、 Safari、 Chrome 和 Opera。
瀏覽器按照引擎分類:
- Trident引擎:Internet Explorer
- Webkit引擎:Chrome(28版本後基於blink,blink是webkit的一個分支)和Safari
- Gecko引擎:Firefox
- Presto引擎:早期Opera採用,後用webkit引擎。
二、瀏覽器的主要構成
瀏覽器的主要元件包括:
- 使用者介面:包括位址列、後退/前進按鈕、書籤目錄等,也就是你所看到的除了用來顯示你所請求頁面的主視窗之外的其他部分。
- 瀏覽器引擎:用來查詢及操作渲染引擎的介面。
- 渲染引擎:用來顯示請求的內容,例如,如果請求內容為html,它負責解析html及css,並將解析後的結果顯示出來。
- 網路:用來完成網路呼叫,例如http請求,它具有平臺無關的介面,可以在不同平臺上工作。
- UI後端:用來繪製類似組合選擇框及對話方塊等基本元件,具有不特定於某個平臺的通用介面,底層使用作業系統的使用者介面。
- JS直譯器:用來解釋執行JS程式碼。
- 資料儲存:屬於持久層,瀏覽器需要在硬碟中儲存類似cookie的各種資料,HTML5定義了web database技術,這是一種輕量級完整的客戶端儲存技術。
瀏覽器主要元件(如圖):
三、渲染引擎
渲染引擎的職責就是渲染,即在瀏覽器視窗中顯示所請求的內容。
預設情況下,渲染引擎可以顯示html、xml文件及圖片,它也可以藉助外掛(一種瀏覽器擴充套件)顯示其他型別資料,例如使用PDF閱讀器外掛,可以顯示PDF格式,將由專門一章講解外掛及擴充套件,這裡只討論渲染引擎最主要的用途——顯示應用了CSS之後的html及圖片。
渲染引擎簡介:
Firefox、Chrome和Safari是基於兩種渲染引擎構建的,Firefox使用Geoko——Mozilla自主研發的渲染引擎,Safari和Chrome都使用webkit。
渲染主流程:
渲染引擎首先通過網路獲得所請求文件的內容,通常以8K分塊的方式完成。
下面是渲染引擎在取得內容之後的基本流程:
解析html以構建dom樹 -> 構建render樹 -> 佈局render樹 -> 繪製render樹
渲染引擎開始解析html,並將標籤轉化為內容樹中的dom節點。接著,它解析外部CSS檔案及style標籤中的樣式資訊。這些樣式資訊以及html中的可見性指令將被用來構建另一棵樹——render樹。
Render樹由一些包含有顏色和大小等屬性的矩形組成,它們將被按照正確的順序顯示到螢幕上。
Render樹構建好了之後,將會執行佈局過程,它將確定每個節點在螢幕上的確切座標。再下一步就是繪製,即遍歷render樹,並使用UI後端層繪製每個節點。
值得注意的是,這個過程是逐步完成的,為了更好的使用者體驗,渲染引擎將會盡可能早的將內容呈現到螢幕上,並不會等到所有的html都解析完成之後再去構建和佈局render樹。它是解析完一部分內容就顯示一部分內容,同時,可能還在通過網路下載其餘內容。
從圖3和4中可以看出,儘管webkit和Gecko使用的術語稍有不同,他們的主要流程基本相同。Gecko稱可見的格式化元素組成的樹為frame樹,每個元素都是一個frame,webkit則使用render樹這個名詞來命名由渲染物件組成的樹。Webkit中元素的定位稱為佈局,而Gecko中稱為迴流。Webkit稱利用dom節點及樣式資訊去構建render樹的過程為attachment,Gecko在html和dom樹之間附加了一層,這層稱為內容接收器,相當製造dom元素的工廠。下面將討論流程中的各個階段。
四、解析
既然解析是渲染引擎中一個非常重要的過程,我們將稍微深入的研究它。首先簡要介紹一下解析。
解析一個文件即將其轉換為具有一定意義的結構——編碼可以理解和使用的東西。解析的結果通常是表達文件結構的節點樹,稱為解析樹或語法樹。
文法(Grammars)
解析基於文件依據的語法規則——文件的語言或格式。每種可被解析的格式必須具有由詞彙及語法規則組成的特定的文法,稱為上下文無關文法。人類語言不具有這一特性,因此不能被一般的解析技術所解析。
解析器-詞法分析器(Parser-Lexer combination)
解析可以分為兩個子過程——語法分析及詞法分析
詞法分析就是將輸入分解為符號,符號是語言的詞彙表——基本有效單元的集合。對於人類語言來說,它相當於我們字典中出現的所有單詞。
語法分析指對語言應用語法規則。
解析器一般將工作分配給兩個元件——詞法分析器(有時也叫分詞器)負責將輸入分解為合法的符號,解析器則根據語言的語法規則分析文件結構,從而構建解析樹,詞法分析器知道怎麼跳過空白和換行之類的無關字元。
解析過程是迭代的,解析器從詞法分析器處取到一個新的符號,並試著用這個符號匹配一條語法規則,如果匹配了一條規則,這個符號對應的節點將被新增到解析樹上,然後解析器請求另一個符號。如果沒有匹配到規則,解析器將在內部儲存該符號,並從詞法分析器取下一個符號,直到所有內部儲存的符號能夠匹配一項語法規則。如果最終沒有找到匹配的規則,解析器將丟擲一個異常,這意味著文件無效或是包含語法錯誤。
轉換(Translation)
很多時候,解析樹並不是最終結果。解析一般在轉換中使用——將輸入文件轉換為另一種格式。編譯就是個例子,編譯器在將一段原始碼編譯為機器碼的時候,先將原始碼解析為解析樹,然後將該樹轉換為一個機器碼文件。
解析器型別(Types of parsers)
有兩種基本的解析器——自頂向下解析及自底向上解析。比較直觀的解釋是,自頂向下解析,檢視語法的最高層結構並試著匹配其中一個;自底向上解析則從輸入開始,逐步將其轉換為語法規則,從底層規則開始直到匹配高層規則。
自底向上解析會掃描輸入直到匹配了一條規則,然後用該規則取代匹配的輸入,直到解析完所有輸入。部分匹配的表示式被放置在解析堆疊中。
自底向上解析器稱為shift reduce解析器,因為輸入向右移動(想象一個指標首先指向輸入開始處,並向右移動),並逐漸簡化為語法規則。
自動化解析(Generating parsers automatically)
解析器生成器這個工具可以自動生成解析器,只需要指定語言的文法——詞彙表及語法規則,它就可以生成一個解析器。建立一個解析器需要對解析有深入的理解,而且手動的建立一個由較好效能的解析器並不容易,所以解析生成器很有用。Webkit使用兩個知名的解析生成器——用於建立語法分析器的Flex及建立解析器的Bison(你可能接觸過Lex和Yacc)。Flex的輸入是一個包含了符號定義的正規表示式,Bison的輸入是用BNF格式表示的語法規則。
HTML解析器(HTML Parser)
HTML解析器的工作是將html標識解析為解析樹。
HTML文法定義(The HTML grammar definition)
W3C組織制定規範定義了HTML的詞彙表和語法。
非上下文無關文法(Not a context free grammar)
正如在解析簡介中提到的,上下文無關文法的語法可以用類似BNF的格式來定義。
不幸的是,所有的傳統解析方式都不適用於html(當然我提出它們並不只是因為好玩,它們將用來解析css和js),html不能簡單的用解析所需的上下文無關文法來定義。
Html有一個正式的格式定義——DTD(Document Type Definition文件型別定義)——但它並不是上下文無關文法,html更接近於xml,現在有很多可用的xml解析器,html有個xml的變體——xhtml,它們間的不同在於,html更寬容,它允許忽略一些特定標籤,有時可以省略開始或結束標籤。總的來說,它是一種soft語法,不像xml呆板、固執。
顯然,這個看起來很小的差異卻帶來了很大的不同。一方面,這是html流行的原因——它的寬容使web開發人員的工作更加輕鬆,但另一方面,這也使很難去寫一個格式化的文法。所以,html的解析並不簡單,它既不能用傳統的解析器解析,也不能用xml解析器解析。
HTML DTD
Html適用DTD格式進行定義,這一格式是用於定義SGML家族的語言,包括了對所有允許元素及它們的屬性和層次關係的定義。正如前面提到的,html DTD並沒有生成一種上下文無關文法。
DTD有一些變種,標準模式只遵守規範,而其他模式則包含了對瀏覽器過去所使用標籤的支援,這麼做是為了相容以前內容。最新的標準DTD在
DOM
輸出的樹,也就是解析樹,是由DOM元素及屬性節點組成的。DOM是文件物件模型的縮寫,它是html文件的物件表示,作為html元素的外部介面供js等呼叫。
樹的根是“document”物件。