|
目錄
一、介紹
二、渲染引擎
三、解析與DOM樹構(gòu)建
四、渲染樹構(gòu)建
五、布局
六、繪制
七、動態(tài)變化
八、渲染引擎的線程
九、CSS2可視模型
英文原文:How Browsers Work: Behind the Scenes of Modern Web Browsers
瀏覽器可以被認(rèn)為是使用最廣泛的軟件,本文將介紹瀏覽器的工作原理,我們將看到,從你在地址欄輸入google.com到你看到google主頁過程中都發(fā)生了什么。
將討論的瀏覽器
今天,有五種主流瀏覽器——IE、Firefox、Safari、Chrome及Opera。
本文將基于一些開源瀏覽器的例子——Firefox、Chrome及Safari,Safari是部分開源的。
根據(jù)W3C(World Wide Web Consortium萬維網(wǎng)聯(lián)盟)的瀏覽器統(tǒng)計(jì)數(shù)據(jù),當(dāng)前(2011年5月),F(xiàn)irefox、Safari及Chrome的市場占有率綜合已接近60%。(原文為2009年10月,數(shù)據(jù)沒有太大變化)因此,可以說開源瀏覽器已經(jīng)占據(jù)了瀏覽器市場的半壁江山。
瀏覽器的主要功能
瀏覽器的主要功能是將用戶選擇的web資源呈現(xiàn)出來,它需要從服務(wù)器請求資源,并將其顯示在瀏覽器窗口中,資源的格式通常是HTML,也包括PDF、image及其他格式。用戶用URI(Uniform Resource Identifier統(tǒng)一資源標(biāo)識符)來指定所請求資源的位置,在網(wǎng)絡(luò)一章有更多討論。
HTML和CSS規(guī)范中規(guī)定了瀏覽器解釋html文檔的方式,由W3C組織對這些規(guī)范進(jìn)行維護(hù),W3C是負(fù)責(zé)制定web標(biāo)準(zhǔn)的組織。
HTML規(guī)范的最新版本是HTML4(http://www.w3.org/TR/html401/),HTML5還在制定中(譯注:兩年前),最新的CSS規(guī)范版本是2(http://www.w3.org/TR/CSS2),CSS3也還正在制定中(譯注:同樣兩年前)。
這些年來,瀏覽器廠商紛紛開發(fā)自己的擴(kuò)展,對規(guī)范的遵循并不完善,這為web開發(fā)者帶來了嚴(yán)重的兼容性問題。
但是,瀏覽器的用戶界面則差不多,常見的用戶界面元素包括:
- 用來輸入U(xiǎn)RI的地址欄
- 前進(jìn)、后退按鈕
- 書簽選項(xiàng)
- 用于刷新及暫停當(dāng)前加載文檔的刷新、暫停按鈕
- 用于到達(dá)主頁的主頁按鈕
奇怪的是,并沒有哪個(gè)正式公布的規(guī)范對用戶界面做出規(guī)定,這些是多年來各瀏覽器廠商之間相互模仿和不斷改進(jìn)的結(jié)果。
HTML5并沒有規(guī)定瀏覽器必須具有的UI元素,但列出了一些常用元素,包括地址欄、狀態(tài)欄及工具欄。還有一些瀏覽器有自己專有的功能,比如Firefox的下載管理。更多相關(guān)內(nèi)容將在后面討論用戶界面時(shí)介紹。
瀏覽器的主要構(gòu)成(High Level Structure)
瀏覽器的主要組件包括:
1. 用戶界面 - 包括地址欄、后退/前進(jìn)按鈕、書簽?zāi)夸浀?,也就是你所看到的除了用來顯示你所請求頁面的主窗口之外的其他部分。
2. 瀏覽器引擎 - 用來查詢及操作渲染引擎的接口。
3. 渲染引擎 - 用來顯示請求的內(nèi)容,例如,如果請求內(nèi)容為html,它負(fù)責(zé)解析html及css,并將解析后的結(jié)果顯示出來。
4. 網(wǎng)絡(luò) - 用來完成網(wǎng)絡(luò)調(diào)用,例如http請求,它具有平臺無關(guān)的接口,可以在不同平臺上工作。
5. UI后端 - 用來繪制類似組合選擇框及對話框等基本組件,具有不特定于某個(gè)平臺的通用接口,底層使用操作系統(tǒng)的用戶接口。
6. JS解釋器 - 用來解釋執(zhí)行JS代碼。
7. 數(shù)據(jù)存儲 - 屬于持久層,瀏覽器需要在硬盤中保存類似cookie的各種數(shù)據(jù),HTML5定義了web database技術(shù),這是一種輕量級完整的客戶端存儲技術(shù)
圖1:瀏覽器主要組件
需要注意的是,不同于大部分瀏覽器,Chrome為每個(gè)Tab分配了各自的渲染引擎實(shí)例,每個(gè)Tab就是一個(gè)獨(dú)立的進(jìn)程。
對于構(gòu)成瀏覽器的這些組件,后面會逐一詳細(xì)討論。
二、渲染引擎(The rendering engine)
渲染引擎的職責(zé)就是渲染,即在瀏覽器窗口中顯示所請求的內(nèi)容。
默認(rèn)情況下,渲染引擎可以顯示html、xml文檔及圖片,它也可以借助插件(一種瀏覽器擴(kuò)展)顯示其他類型數(shù)據(jù),例如使用PDF閱讀器插件,可以顯示PDF格式,將由專門一章講解插件及擴(kuò)展,這里只討論渲染引擎最主要的用途——顯示應(yīng)用了CSS之后的html及圖片。
渲染引擎簡介
本文所討論的瀏覽器——Firefox、Chrome和Safari是基于兩種渲染引擎構(gòu)建的,F(xiàn)irefox使用Geoko——Mozilla自主研發(fā)的渲染引擎,Safari和Chrome都使用webkit。
Webkit是一款開源渲染引擎,它本來是為Linux平臺研發(fā)的,后來由Apple移植到Mac及Windows上,相關(guān)內(nèi)容請參考http://webkit.org。
渲染主流程(The main flow)
渲染引擎首先通過網(wǎng)絡(luò)獲得所請求文檔的內(nèi)容,通常以8K分塊的方式完成。
下面是渲染引擎在取得內(nèi)容之后的基本流程:
解析html以構(gòu)建dom樹 -> 構(gòu)建render樹 -> 布局render樹 -> 繪制render樹
圖2:渲染引擎基本流程
渲染引擎開始解析html,并將標(biāo)簽轉(zhuǎn)化為內(nèi)容樹中的dom節(jié)點(diǎn)。接著,它解析外部CSS文件及style標(biāo)簽中的樣式信息。這些樣式信息以及html中的可見性指令將被用來構(gòu)建另一棵樹——render樹。
Render樹由一些包含有顏色和大小等屬性的矩形組成,它們將被按照正確的順序顯示到屏幕上。
Render樹構(gòu)建好了之后,將會執(zhí)行布局過程,它將確定每個(gè)節(jié)點(diǎn)在屏幕上的確切坐標(biāo)。再下一步就是繪制,即遍歷render樹,并使用UI后端層繪制每個(gè)節(jié)點(diǎn)。
值得注意的是,這個(gè)過程是逐步完成的,為了更好的用戶體驗(yàn),渲染引擎將會盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會等到所有的html都解析完成之后再去構(gòu)建和布局render樹。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容,同時(shí),可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容。
圖3:webkit主流程
圖4:Mozilla的Geoko渲染引擎主流程
從圖3和4中可以看出,盡管webkit和Gecko使用的術(shù)語稍有不同,他們的主要流程基本相同。Gecko稱可見的格式化元素組成的樹為frame樹,每個(gè)元素都是一個(gè)frame,webkit則使用render樹這個(gè)名詞來命名由渲染對象組成的樹。Webkit中元素的定位稱為布局,而Gecko中稱為回流。Webkit稱利用dom節(jié)點(diǎn)及樣式信息去構(gòu)建render樹的過程為attachment,Gecko在html和dom樹之間附加了一層,這層稱為內(nèi)容接收器,相當(dāng)制造dom元素的工廠。下面將討論流程中的各個(gè)階段。
三、解析與DOM樹構(gòu)建(Parsing and DOM tree construction)
解析(Parsing-general)
既然解析是渲染引擎中一個(gè)非常重要的過程,我們將稍微深入的研究它。首先簡要介紹一下解析。
解析一個(gè)文檔即將其轉(zhuǎn)換為具有一定意義的結(jié)構(gòu)——編碼可以理解和使用的東西。解析的結(jié)果通常是表達(dá)文檔結(jié)構(gòu)的節(jié)點(diǎn)樹,稱為解析樹或語法樹。
例如,解析“2+3-1”這個(gè)表達(dá)式,可能返回這樣一棵樹。
圖5:數(shù)學(xué)表達(dá)式樹節(jié)點(diǎn)
文法(Grammars)
解析基于文檔依據(jù)的語法規(guī)則——文檔的語言或格式。每種可被解析的格式必須具有由詞匯及語法規(guī)則組成的特定的文法,稱為上下文無關(guān)文法。人類語言不具有這一特性,因此不能被一般的解析技術(shù)所解析。
解析器-詞法分析器(Parser-Lexer combination)
解析可以分為兩個(gè)子過程——語法分析及詞法分析
詞法分析就是將輸入分解為符號,符號是語言的詞匯表——基本有效單元的集合。對于人類語言來說,它相當(dāng)于我們字典中出現(xiàn)的所有單詞。
語法分析指對語言應(yīng)用語法規(guī)則。
解析器一般將工作分配給兩個(gè)組件——詞法分析器(有時(shí)也叫分詞器)負(fù)責(zé)將輸入分解為合法的符號,解析器則根據(jù)語言的語法規(guī)則分析文檔結(jié)構(gòu),從而構(gòu)建解析樹,詞法分析器知道怎么跳過空白和換行之類的無關(guān)字符。
圖6:從源文檔到解析樹
解析過程是迭代的,解析器從詞法分析器處取到一個(gè)新的符號,并試著用這個(gè)符號匹配一條語法規(guī)則,如果匹配了一條規(guī)則,這個(gè)符號對應(yīng)的節(jié)點(diǎn)將被添加到解析樹上,然后解析器請求另一個(gè)符號。如果沒有匹配到規(guī)則,解析器將在內(nèi)部保存該符號,并從詞法分析器取下一個(gè)符號,直到所有內(nèi)部保存的符號能夠匹配一項(xiàng)語法規(guī)則。如果最終沒有找到匹配的規(guī)則,解析器將拋出一個(gè)異常,這意味著文檔無效或是包含語法錯(cuò)誤。
轉(zhuǎn)換(Translation)
很多時(shí)候,解析樹并不是最終結(jié)果。解析一般在轉(zhuǎn)換中使用——將輸入文檔轉(zhuǎn)換為另一種格式。編譯就是個(gè)例子,編譯器在將一段源碼編譯為機(jī)器碼的時(shí)候,先將源碼解析為解析樹,然后將該樹轉(zhuǎn)換為一個(gè)機(jī)器碼文檔。
圖7:編譯流程
解析實(shí)例Parsing example
圖5中,我們從一個(gè)數(shù)學(xué)表達(dá)式構(gòu)建了一個(gè)解析樹,這里定義一個(gè)簡單的數(shù)學(xué)語言來看下解析過程。
詞匯表:我們的語言包括整數(shù)、加號及減號。
語法:
1. 該語言的語法基本單元包括表達(dá)式、term及操作符
2. 該語言可以包括多個(gè)表達(dá)式
3. 一個(gè)表達(dá)式定義為兩個(gè)term通過一個(gè)操作符連接
4. 操作符可以是加號或減號
5. term可以是一個(gè)整數(shù)或一個(gè)表達(dá)式
現(xiàn)在來分析一下“2+3-1”這個(gè)輸入
第一個(gè)匹配規(guī)則的子字符串是“2”,根據(jù)規(guī)則5,它是一個(gè)term,第二個(gè)匹配的是“2+3”,它符合第2條規(guī)則——一個(gè)操作符連接兩個(gè)term,下一次匹配發(fā)生在輸入的結(jié)束處。“2+3-1”是一個(gè)表達(dá)式,因?yàn)槲覀円呀?jīng)知道“2+3”是一個(gè)term,所以我們有了一個(gè)term緊跟著一個(gè)操作符及另一個(gè)term。“2++”將不會匹配任何規(guī)則,因此是一個(gè)無效輸入。
詞匯表及語法的定義
詞匯表通常利用正則表達(dá)式來定義。
例如上面的語言可以定義為:
INTEGER:0|[1-9][0-9]*
PLUS:+
MINUS:-
正如看到的,這里用正則表達(dá)式定義整數(shù)。
語法通常用BNF格式定義,我們的語言可以定義為:
expression := term operation term
operation := PLUS | MINUS
term := INTEGER | expression
如果一個(gè)語言的文法是上下文無關(guān)的,則它可以用正則解析器來解析。對上下文無關(guān)文法的一個(gè)直觀的定義是,該文法可以用BNF來完整的表達(dá)。可查看http://en.wikipedia.org/wiki/Context-free_grammar。
解析器類型(Types of parsers)
有兩種基本的解析器——自頂向下解析及自底向上解析。比較直觀的解釋是,自頂向下解析,查看語法的最高層結(jié)構(gòu)并試著匹配其中一個(gè);自底向上解析則從輸入開始,逐步將其轉(zhuǎn)換為語法規(guī)則,從底層規(guī)則開始直到匹配高層規(guī)則。
來看一下這兩種解析器如何解析上面的例子:
自頂向下解析器從最高層規(guī)則開始——它先識別出“2+3“,將其視為一個(gè)表達(dá)式,然后識別出”2+3-1“為一個(gè)表達(dá)式(識別表達(dá)式的過程中匹配了其他規(guī)則,但出發(fā)點(diǎn)是最高層規(guī)則)。
自底向上解析會掃描輸入直到匹配了一條規(guī)則,然后用該規(guī)則取代匹配的輸入,直到解析完所有輸入。部分匹配的表達(dá)式被放置在解析堆棧中。
Stack | Input |
2 + 3 – 1 | |
term | + 3 - 1 |
term operation | 3 – 1 |
expression | - 1 |
expression operation | 1 |
expression |
自底向上解析器稱為shift reduce解析器,因?yàn)檩斎胂蛴?a href=/yuedu/yidong/ target=_blank class=infotextkey>移動(想象一個(gè)指針首先指向輸入開始處,并向右移動),并逐漸簡化為語法規(guī)則。
自動化解析(Generating parsers automatically)
解析器生成器這個(gè)工具可以自動生成解析器,只需要指定語言的文法——詞匯表及語法規(guī)則,它就可以生成一個(gè)解析器。創(chuàng)建一個(gè)解析器需要對解析有深入的理解,而且手動的創(chuàng)建一個(gè)由較好性能的解析器并不容易,所以解析生成器很有用。Webkit使用兩個(gè)知名的解析生成器——用于創(chuàng)建語法分析器的Flex及創(chuàng)建解析器的Bison(你可能接觸過Lex和Yacc)。Flex的輸入是一個(gè)包含了符號定義的正則表達(dá)式,Bison的輸入是用BNF格式表示的語法規(guī)則。
HTML解析器(HTML Parser)
HTML解析器的工作是將html標(biāo)識解析為解析樹。
HTML文法定義(The HTML grammar definition)
W3C組織制定規(guī)范定義了HTML的詞匯表和語法。
非上下文無關(guān)文法(Not a context free grammar)
正如在解析簡介中提到的,上下文無關(guān)文法的語法可以用類似BNF的格式來定義。
不幸的是,所有的傳統(tǒng)解析方式都不適用于html(當(dāng)然我提出它們并不只是因?yàn)楹猛?,它們將用來解析css和js),html不能簡單的用解析所需的上下文無關(guān)文法來定義。
Html有一個(gè)正式的格式定義——DTD(Document Type Definition文檔類型定義)——但它并不是上下文無關(guān)文法,html更接近于xml,現(xiàn)在有很多可用的xml解析器,html有個(gè)xml的變體——xhtml,它們間的不同在于,html更寬容,它允許忽略一些特定標(biāo)簽,有時(shí)可以省略開始或結(jié)束標(biāo)簽??偟膩碚f,它是一種soft語法,不像xml呆板、固執(zhí)。
顯然,這個(gè)看起來很小的差異卻帶來了很大的不同。一方面,這是html流行的原因——它的寬容使web開發(fā)人員的工作更加輕松,但另一方面,這也使很難去寫一個(gè)格式化的文法。所以,html的解析并不簡單,它既不能用傳統(tǒng)的解析器解析,也不能用xml解析器解析。
HTML DTD
Html適用DTD格式進(jìn)行定義,這一格式是用于定義SGML家族的語言,包括了對所有允許元素及它們的屬性和層次關(guān)系的定義。正如前面提到的,html DTD并沒有生成一種上下文無關(guān)文法。
DTD有一些變種,標(biāo)準(zhǔn)模式只遵守規(guī)范,而其他模式則包含了對瀏覽器過去所使用標(biāo)簽的支持,這么做是為了兼容以前內(nèi)容。最新的標(biāo)準(zhǔn)DTD在http://www.w3.org/TR/html4/strict.dtd
DOM
輸出的樹,也就是解析樹,是由DOM元素及屬性節(jié)點(diǎn)組成的。DOM是文檔對象模型的縮寫,它是html文檔的對象表示,作為html元素的外部接口供js等調(diào)用。
樹的根是“document”對象。
DOM和標(biāo)簽基本是一一對應(yīng)的關(guān)系,例如,如下的標(biāo)簽:
<html>
<body>
<p>
Hello DOM
</p>
<div><img src=”example.png” /></div>
</body>
</html>
it知識庫:前端必讀:瀏覽器內(nèi)部工作原理,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。