源文件:http://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/css
寫的很好,雖然長仍是值得一看。涉及到解析、css計算等等算法有一些具體幫助理解的實例,挺複雜的,建議花點時間閱讀原文。html
· user interface- 包括地址欄、前進/後退按鈕、書籤菜單等。除了瀏覽器主窗口顯示的您請求的頁面外,其餘顯示的各個部分都屬於用戶界面。html5
browser engine -在用戶界面和呈現引擎之間傳送指令。web
rendering engine -負責顯示請求的內容。若是請求的內容是 HTML,它就負責解析HTML 和 CSS 內容,並將解析後的內容顯示在屏幕上。算法
networking -用於網絡調用,好比HTTP 請求。其接口與平臺無關,併爲全部平臺提供底層實現。數據庫
UI backend -用於繪製基本的窗口小部件,好比組合框和窗口。其公開了與平臺無關的通用接口,而在底層使用操做系統的用戶界面方法。後端
JavaScript interpreter。用於解析和執行JavaScript 代碼。瀏覽器
data Persistence。這是持久層。瀏覽器須要在硬盤上保存各類數據,例如Cookie。新的 HTML 規範(HTML5) 定義了「網絡數據庫」,這是一個完整(可是輕便)的瀏覽器內數據庫。網絡
值得注意的是,和大多數瀏覽器不一樣,Chrome瀏覽器的每一個標籤頁都分別對應一個呈現引擎實例。每一個標籤頁都是一個獨立的進程。併發
本文所討論的瀏覽器(Firefox、Chrome 瀏覽器和 Safari)是基於兩種呈現引擎構建的。Firefox 使用的是 Gecko,這是 Mozilla 公司「自制」的呈現引擎。而 Safari 和 Chrome 瀏覽器使用的都是 WebKit。
呈現引擎一開始會從網絡層獲取請求文檔的內容,內容的大小通常限制在 8000 個塊之內。
而後進行以下所示的基本流程:
圖:呈現引擎的基本流程。呈現引擎將開始解析 HTML 文檔,並將各標記逐個轉化成「內容樹」上的 DOM 節點。同時也會解析外部 CSS 文件以及樣式元素中的樣式數據。HTML 中這些帶有視覺指令的樣式信息將用於建立另外一個樹結構:呈現樹。
呈現樹包含多個帶有視覺屬性(如顏色和尺寸)的矩形。這些矩形的排列順序就是它們將在屏幕上顯示的順序。
呈現樹構建完畢以後,進入「佈局」處理階段,也就是爲每一個節點分配一個應出如今屏幕上的確切座標。下一個階段是繪製 - 呈現引擎會遍歷呈現樹,由用戶界面後端層將每一個節點繪製出來。
須要着重指出的是,這是一個漸進的過程。爲達到更好的用戶體驗,呈現引擎會力求儘快將內容顯示在屏幕上。它沒必要等到整個 HTML 文檔解析完畢以後,就會開始構建呈現樹和設置佈局。在不斷接收和處理來自網絡的其他內容的同時,呈現引擎會將部份內容解析並顯示出來。
從圖 3 和圖 4 能夠看出,雖然 WebKit 和 Gecko 使用的術語略有不一樣,但總體流程是基本相同的。
HTML 沒法用常規的自上而下或自下而上的解析器進行解析。
緣由在於:
document.write
,就會添加額外的標記,這樣解析過程實際上就更改了輸入內容。因爲不能使用常規的解析技術,瀏覽器就建立了自定義的解析器來解析 HTML。
HTML5 規範詳細地描述瞭解析算法。此算法由兩個階段組成:標記化和樹構建
經過一個簡單的示例來幫助你們理解其原理。
基本示例 - 將下面的 HTML 代碼標記化:
<html> <body> Hello world </body> </html>
初始狀態是數據狀態。遇到字符 <
時,狀態更改成「標記打開狀態」。接收一個 a-z
字符會建立「起始標記」,狀態更改成「標記名稱狀態」。這個狀態會一直保持到接收 >
字符。在此期間接收的每一個字符都會附加到新的標記名稱上。在本例中,咱們建立的標記是 html
標記。
遇到 >
標記時,會發送當前的標記,狀態改回「數據狀態」。<body>
標記也會進行一樣的處理。目前 html
和 body
標記均已發出(發給樹構造器)。如今咱們回到「數據狀態」。接收到Hello world
中的 H
字符時,將建立併發送字符標記,直到接收 </body>
中的 <
。咱們將爲 Hello world
中的每一個字符都發送一個字符標記。
如今咱們回到「標記打開狀態」。接收下一個輸入字符 /
時,會建立 end tag token
並改成「標記名稱狀態」。咱們會再次保持這個狀態,直到接收 >
。而後將發送新的標記,並回到「數據狀態」。</html>
輸入也會進行一樣的處理
在建立解析器的同時,也會建立 Document 對象。
網絡的模型是同步的。網頁做者但願解析器遇到 <script> 標記時當即解析並執行腳本。文檔的解析將中止,直到腳本執行完畢。若是腳本是外部的,那麼解析過程會中止,直到從網絡同步抓取資源完成後再繼續。此模型已經使用了多年,也在 HTML4 和 HTML5 規範中進行了指定。做者也能夠將腳本標註爲「defer」,這樣它就不會中止文檔解析,而是等到解析結束才執行。HTML5 增長了一個選項,可將腳本標記爲異步,以便由其餘線程解析和執行。
WebKit 和 Firefox 都進行了這項優化。在執行腳本時,其餘線程會解析文檔的其他部分,找出並加載須要經過網絡加載的其餘資源。經過這種方式,資源能夠在並行鏈接上加載,從而提升整體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工做交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的引用。
另外一方面,樣式表有着不一樣的模型。理論上來講,應用樣式表不會更改 DOM 樹,所以彷佛沒有必要等待樣式表並中止文檔解析。但這涉及到一個問題,就是腳本在文檔解析階段會請求樣式信息。若是當時尚未加載和解析樣式,腳本就會得到錯誤的回覆,這樣顯然會產生不少問題。這看上去是一個非典型案例,但事實上很是廣泛。Firefox 在樣式表加載和解析的過程當中,會禁止全部腳本。而對於 WebKit 而言,僅當腳本嘗試訪問的樣式屬性可能受還沒有加載的樣式表影響時,它纔會禁止該腳本。
圖:呈現樹及其對應的 DOM 樹 (3.1)。初始容器 block 爲「viewport」,而在 WebKit 中則爲「RenderView」對象。
while (!mExiting) NS_ProcessNextEvent(thread);