《深入理解Android》一2.1 浏览器工作原理概述
本節(jié)書(shū)摘來(lái)自華章出版社《深入理解Android》一書(shū)中的第2章,第2.1節(jié),作者孟德國(guó) 王耀龍 周金利 黎歡,更多章節(jié)內(nèi)容可以訪問(wèn)云棲社區(qū)“華章計(jì)算機(jī)”公眾號(hào)查看
2.1 瀏覽器工作原理概述
眾所周知,萬(wàn)維網(wǎng)(World Wide Web,WWW)以統(tǒng)一資源定位符(Uniform Resource Locator,URL)作為地址空間編碼,以超文本傳送協(xié)議(HyperText Transfer Protocol,HTTP)請(qǐng)求和應(yīng)答,以超文本標(biāo)記語(yǔ)言(HyperText Markup Language,HTML)記錄并以超鏈接(hyperlink)互相關(guān)聯(lián)起來(lái)的網(wǎng)頁(yè)(web page)文檔作為內(nèi)容單元,構(gòu)成了人類(lèi)有史以來(lái)最為龐大的資料信息庫(kù)。瀏覽器(browser application)即是專(zhuān)門(mén)用來(lái)訪問(wèn)和瀏覽萬(wàn)維網(wǎng)頁(yè)面的客戶端軟件,也是現(xiàn)代計(jì)算機(jī)系統(tǒng)中應(yīng)用最為廣泛的軟件之一,其重要性不言而喻。瀏覽器內(nèi)部最主要也是最重要的模塊是負(fù)責(zé)頁(yè)面渲染的排版引擎(layout engine),也可稱(chēng)作瀏覽器的內(nèi)核(kernel),其余的部分可統(tǒng)稱(chēng)為瀏覽器的外殼(browser shell)。
下面將從頁(yè)面、排版引擎和瀏覽器外殼應(yīng)用三個(gè)方面對(duì)萬(wàn)維網(wǎng)和瀏覽器技術(shù)的基本概念和原理逐一地做簡(jiǎn)單介紹。
2.1.1 頁(yè)面
現(xiàn)代Web Page通常由三部分組成:描述頁(yè)面結(jié)構(gòu)和內(nèi)容的HTML語(yǔ)言,控制頁(yè)面動(dòng)態(tài)邏輯的JavaScript腳本,設(shè)定頁(yè)面風(fēng)格樣式的層疊樣式表(Cascading Style Sheets,CSS)。
HTML是為創(chuàng)建和描述可在瀏覽器中展現(xiàn)的網(wǎng)頁(yè)信息而設(shè)計(jì)的一種文本格式標(biāo)記語(yǔ)言,最初于1982年由Tim Berners-Lee創(chuàng)建,后來(lái)成為國(guó)際標(biāo)準(zhǔn),由萬(wàn)維網(wǎng)聯(lián)盟(W3C)維護(hù)。HTML由SGML(Standard Generalized Markup Language)簡(jiǎn)化發(fā)展而來(lái),能夠結(jié)構(gòu)化地表示文檔的構(gòu)成和內(nèi)容(如標(biāo)題、段落、文本、表格),以及一定的外觀(如寬、高、顏色)和語(yǔ)義(如注釋、鏈接)。HTML頁(yè)面由多種尖括號(hào)<>包圍起來(lái)的標(biāo)簽元素以樹(shù)形結(jié)構(gòu)組成,其頂級(jí)標(biāo)簽為,內(nèi)容標(biāo)簽為
JavaScript是一種內(nèi)置于瀏覽器的動(dòng)態(tài)、弱類(lèi)型、基于原型的網(wǎng)頁(yè)腳本語(yǔ)言。一般來(lái)說(shuō),完整的JavaScript應(yīng)該包括以下幾個(gè)部分:
ECMAScript:描述了該語(yǔ)言的語(yǔ)法和基本對(duì)象;
文檔對(duì)象模型(DOM):描述處理網(wǎng)頁(yè)內(nèi)容的方法和接口;
瀏覽器對(duì)象模型(BOM):描述與瀏覽器進(jìn)行交互的方法和接口。
JavaScript的出現(xiàn)使得網(wǎng)頁(yè)由單純的靜態(tài)HTML變成動(dòng)態(tài)可編程的DHTML,開(kāi)發(fā)者可用JavaScript來(lái)完成讀寫(xiě)DOM,向頁(yè)面添加交互行為,對(duì)瀏覽器事件做出響應(yīng),創(chuàng)建和發(fā)起網(wǎng)絡(luò)請(qǐng)求等許多工作。
層疊樣式表(CSS)的發(fā)明是為了將網(wǎng)頁(yè)的內(nèi)容描述與顯示風(fēng)格的描述分隔出來(lái),HTML中只包含結(jié)構(gòu)和內(nèi)容的描述信息,CSS則只包含樣式的描述信息。單獨(dú)把一些顯示風(fēng)格信息如字體顏色、背景、排版方式等統(tǒng)一放在CSS文本中,可以大大簡(jiǎn)化HTML文件,同時(shí)增強(qiáng)可讀性和修改靈活性。
Web Page一般由前端(front end)開(kāi)發(fā)設(shè)計(jì)人員直接編寫(xiě)或者由服務(wù)器端的腳本動(dòng)態(tài)生成,通過(guò)Web服務(wù)器以HTTP協(xié)議發(fā)布,供瀏覽器訪問(wèn),這種方式即是通常所說(shuō)的B/S架構(gòu)(Browser/Server Architecture)。
2.1.2 內(nèi)核
瀏覽器的內(nèi)核或稱(chēng)排版引擎,負(fù)責(zé)請(qǐng)求網(wǎng)絡(luò)頁(yè)面資源加以解析排版并呈現(xiàn)給用戶。從資源的下載到最終的頁(yè)面展現(xiàn),可簡(jiǎn)單地理解成一個(gè)線性串聯(lián)的變換過(guò)程的組合,原始輸入為URL地址,最終輸出為頁(yè)面Bitmap,中間依次經(jīng)過(guò)了Loader、Parser、Layout和Paint模塊,如圖2-1所示。
Loader模塊(如圖2-2所示)負(fù)責(zé)處理所有的HTTP請(qǐng)求以及網(wǎng)絡(luò)資源的緩存,相當(dāng)于是從URL輸入到Page Resource輸出的變換過(guò)程。HTML頁(yè)面中通常有外鏈的JS/CSS/Image資源,為了不阻塞后續(xù)解析過(guò)程,一般會(huì)有兩個(gè)IO管道同時(shí)存在,一個(gè)負(fù)責(zé)主頁(yè)面下載,一個(gè)負(fù)責(zé)各種外鏈資源的下載。
雖然大部分情況下不同資源可以并發(fā)下載異步解析(如圖片資源可以在主頁(yè)面解析顯示完成后再被顯示),但JS腳本可能會(huì)要求改變頁(yè)面,因此有時(shí)保持執(zhí)行順序和下載管道后續(xù)處理的阻塞是不可避免的。
Parser模塊主要負(fù)責(zé)解析HTML頁(yè)面,完成從HTML文本到HTML語(yǔ)法樹(shù)再到文檔對(duì)象樹(shù)(Document Object Model Tree,DOM Tree)的映射過(guò)程。
HTML語(yǔ)法樹(shù)生成如圖2-3所示是一個(gè)典型的語(yǔ)法解析過(guò)程,可以分成兩個(gè)子過(guò)程:詞法解析和語(yǔ)法解析。詞法解析按照詞法規(guī)則(如正則表達(dá)式)將HTML文本分割成大量的標(biāo)記(token),并去除其中無(wú)關(guān)的字符如空格。語(yǔ)法解析按照語(yǔ)法規(guī)則(如上下文無(wú)關(guān)文法)匹配Token序列生成語(yǔ)法樹(shù),通常有自上而下和自下而上兩種匹配方式。
瀏覽器內(nèi)核中對(duì)HTML頁(yè)面真正的內(nèi)部表示并不是語(yǔ)法樹(shù),而是W3C組織規(guī)范的文檔對(duì)象模型 (Document Object Model,DOM)。DOM也是樹(shù)形結(jié)構(gòu),以Document對(duì)象為根。DOM節(jié)點(diǎn)基本和HTML語(yǔ)法樹(shù)節(jié)點(diǎn)一一對(duì)應(yīng),因此在語(yǔ)法解析過(guò)程中,通常直接生成最終的DOM樹(shù)。下面這個(gè)HTML文檔對(duì)應(yīng)的語(yǔ)法樹(shù)如圖2-4所示,而實(shí)際構(gòu)建的DOM樹(shù)如圖2-5所示。
不同的頁(yè)面標(biāo)簽對(duì)應(yīng)不同類(lèi)型的DOM樹(shù)節(jié)點(diǎn),如
標(biāo)簽會(huì)對(duì)應(yīng)HTMLDiv-Element。DOM節(jié)點(diǎn)類(lèi)型構(gòu)成一個(gè)繼承體系,詳情可參見(jiàn)WebKit源碼中WebCore/dom和WebCore/html兩個(gè)目錄。頁(yè)面中所有的CSS由樣式表CSSStyleSheet集合構(gòu)成,而CSSStyleSheet是一系列CSSRule的集合,每一條CSSRule則由選擇器CSSStyleSelector部分和聲明CSSStyleDeclaration部分構(gòu)成,而CSSStyleDeclaration是CSS屬性和值的Key-Value集合。圖2-6顯示了某一CSS樣式表經(jīng)過(guò)CSSParser解析后在瀏覽內(nèi)核中的基本表示。
CSS解析完畢后會(huì)進(jìn)行CSSRule的匹配過(guò)程,即尋找滿足每條CSS規(guī)則Selector部分的HTML元素,然后將其Declaration部分應(yīng)用于該元素。實(shí)際的規(guī)則匹配過(guò)程會(huì)考慮到默認(rèn)和繼承的CSS屬性、匹配的效率及規(guī)則的優(yōu)先級(jí)等因素。
JavaScript一般由單獨(dú)的腳本引擎解析執(zhí)行,它的作用通常是動(dòng)態(tài)地改變DOM樹(shù)(比如為DOM節(jié)點(diǎn)添加事件響應(yīng)處理函數(shù)),即根據(jù)時(shí)間(timer)或事件(event)映射一棵DOM樹(shù)到另一棵DOM樹(shù)。
簡(jiǎn)單來(lái)說(shuō),經(jīng)過(guò)了Parser模塊的處理,內(nèi)核把頁(yè)面文本轉(zhuǎn)換成了一棵節(jié)點(diǎn)帶CSS Style、會(huì)響應(yīng)自定義事件的Styled DOM樹(shù)。
顧名思義,Layout過(guò)程就是排版,它包含兩大過(guò)程。
步驟1:創(chuàng)建布局樹(shù)。
布局樹(shù)(或者叫做渲染樹(shù)、Render Tree,如圖2-7所示)和DOM樹(shù)大體能一一對(duì)應(yīng),兩者在內(nèi)核中同時(shí)存在但作用不同。DOM樹(shù)是HTML文檔的對(duì)象表示,同時(shí)也作為JavaScript操縱HTML的對(duì)象接口。Render樹(shù)是DOM樹(shù)的排版表示,用以計(jì)算可視DOM節(jié)點(diǎn)的布局信息(如寬、高、坐標(biāo))和后續(xù)階段的繪制顯示。
并非所有DOM節(jié)點(diǎn)都可視,也就是并非所有DOM樹(shù)節(jié)點(diǎn)都會(huì)對(duì)應(yīng)生成一個(gè)Render樹(shù)節(jié)點(diǎn)。例如,
步驟2:計(jì)算布局。
布局就是安排和計(jì)算頁(yè)面中每個(gè)元素大小位置等幾何信息的過(guò)程。HTML 采用流式布局模型,基本的原則是頁(yè)面元素在順序遍歷過(guò)程中依次按從左至右、從上至下的排列方式確定各自的位置區(qū)域。一個(gè)HTML元素對(duì)應(yīng)一個(gè)以CSS盒子模型(如圖2-8所示)描述的方塊區(qū)域,盒子模型決定了內(nèi)容、邊框和邊框內(nèi)外填充區(qū)(Padding、Margin)的大小。HTML元素分成兩個(gè)基本類(lèi)型,Inline和Block。Inline元素不會(huì)換行,按從左到右來(lái)布局。Block元素的出現(xiàn)意味著需要從上至下?lián)Q到下一行來(lái)布局。除了這種基本的順序按照元素的Inline和Block來(lái)進(jìn)行流式布局之外,還有特殊指定的一些布局方式,如Absolute/Fixed/Relative三種定位布局以及Float浮動(dòng)布局。簡(jiǎn)單情況下,布局可以順序遍歷一次Render樹(shù)完成,但也有需要迭代的情況。當(dāng)祖先元素的大小位置依賴(lài)于后代元素或者互相依賴(lài)時(shí),一次遍歷就無(wú)法完成布局,如Table元素的寬高未明確指定而其下某一子元素Tr指定其高度為父Table高度的30%的情況。
經(jīng)過(guò)了Layout階段的處理,我們把帶Style的DOM樹(shù)變換成包含布局信息和繪制信息的Render樹(shù),接下來(lái)的顯示工作就交由Paint模塊進(jìn)行操作了。
Paint模塊負(fù)責(zé)將Render樹(shù)映射成可視的圖形,它會(huì)遍歷Render樹(shù)調(diào)用每個(gè)Render節(jié)點(diǎn)的繪制方法將其內(nèi)容顯示在一塊畫(huà)布或者位圖上,并最終呈現(xiàn)在瀏覽器應(yīng)用窗口中成為用戶看到的實(shí)際頁(yè)面。每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的大小位置等信息都已經(jīng)由Layout階段計(jì)算好了,節(jié)點(diǎn)的內(nèi)容取決于對(duì)應(yīng)的HTML元素,或是文本,或是圖片,或是UI控件。
通常情況下,布局和繪制是相當(dāng)耗時(shí)的操作。如果DOM樹(shù)每次略有改動(dòng)都要重新布局和繪制一次,效率會(huì)相當(dāng)?shù)拖隆R虼?#xff0c;一般瀏覽內(nèi)核都會(huì)實(shí)現(xiàn)一種增量布局和增量繪制的方式。當(dāng)一個(gè)DOM樹(shù)節(jié)點(diǎn)(或者它的子節(jié)點(diǎn))內(nèi)容或者樣式發(fā)生變化時(shí),內(nèi)核會(huì)確定其影響范圍,在布局階段會(huì)標(biāo)記出受該節(jié)點(diǎn)布局影響的其他節(jié)點(diǎn)(比如可能是子節(jié)點(diǎn)),在繪制階段則會(huì)標(biāo)記出一個(gè)Dirty區(qū)域并通知系統(tǒng)重繪。
按照HTML相關(guān)規(guī)范,頁(yè)面元素的CSS屬性也規(guī)定了其繪制順序,如根據(jù)不同Layer必須按順序繪制,否則覆蓋疊加效果會(huì)出現(xiàn)錯(cuò)誤,如元素的邊框輪廓和內(nèi)容背景的繪制次序也有規(guī)定。
基本上瀏覽內(nèi)核的工作原理即如上所述,不同瀏覽器的具體實(shí)現(xiàn)架構(gòu)不盡相同,所采用的術(shù)語(yǔ)名稱(chēng)可能不一樣,但都需要完成上述各個(gè)階段的工作。例如,Mozilla Firefox瀏覽器使用的Gecko排版引擎主要流程如圖2-9所示。
2.1.3 外殼
瀏覽器作為一個(gè)完整軟件,除了對(duì)用戶透明和不可見(jiàn)的渲染引擎作為內(nèi)核外,還需要有供用戶交互使用的外殼UI界面,圖2-10給出了一個(gè)瀏覽器Shell的基本模塊架構(gòu)。目前的主流瀏覽器基本都會(huì)提供如下功能:
地址欄URI輸入;
前進(jìn)后退和刷新停止的控制按鈕;
主頁(yè)、網(wǎng)絡(luò)導(dǎo)航和搜索;
歷史、書(shū)簽和下載管理;
多標(biāo)簽頁(yè)瀏覽和會(huì)話管理;
查找、縮放和全屏;
數(shù)據(jù)持久化如Cookie、LocalStorage等;
選項(xiàng)設(shè)置;
插件和功能擴(kuò)展。
由于Ajax、HTML 5等前端技術(shù)和瀏覽引擎的迅猛發(fā)展,今天的瀏覽器已經(jīng)超出了展現(xiàn)某URL上網(wǎng)頁(yè)內(nèi)容這一基本功能的范疇,網(wǎng)頁(yè)可作為繪圖、辦公、游戲、即時(shí)通信等應(yīng)用的載體。Web App已經(jīng)成為現(xiàn)實(shí),瀏覽器也從單一的工具軟件向Web OS的方向演進(jìn)。每一個(gè)Web Page或Web App可看成對(duì)應(yīng)于傳統(tǒng)操作系統(tǒng)中的一個(gè)Native App,排版引擎作為Kernel執(zhí)行Web App,瀏覽外殼作為GUI Shell供用戶操作使用,多標(biāo)簽瀏覽器相當(dāng)于多任務(wù)操作系統(tǒng),Google的Chrome瀏覽器和由此演變而來(lái)的Chrome OS可看作這一想法的實(shí)施典型。圖2-11描述了Chrome瀏覽器和WebKit排版引擎之間的層次結(jié)構(gòu)和調(diào)用關(guān)系,圖2-12則給出了Chrome多進(jìn)程設(shè)計(jì)的核心架構(gòu)。
總結(jié)
以上是生活随笔為你收集整理的《深入理解Android》一2.1 浏览器工作原理概述的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 线性规划问题(一)
- 下一篇: 信息系统和信息系统集成的概念