這篇文章帶給大家的內容是關於瀏覽器解析渲染HTML文件的過程詳解(圖文),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
瀏覽器的工作原理
一、瀏覽器的高層結構
瀏覽器的主要元件為:
1、使用者介面- 包含網址列、前進/後退按鈕、書籤選單等。除了瀏覽器主視窗顯示的您要求的頁面外,其他顯示的各個部分都屬於使用者介面。2、瀏覽器引擎 - 在使用者介面和呈現引擎之間傳送指令。
3、呈現引擎 - 負責顯示請求的內容。如果要求的內容是 HTML,它就負責解析 HTML 和 CSS 內容,並將解析後的內容顯示在螢幕上。
4、網路 - 用於網路調用,例如 HTTP 請求。其介面與平台無關,並為所有平台提供底層實作。
5、使用者介面後端 - 用於繪製基本的視窗小部件,例如組合框和視窗。其公開了與平台無關的通用接口,而在底層使用作業系統的使用者介面方法。
6、JavaScript 解譯器。用於解析和執行 JavaScript 程式碼。
7、資料儲存。這是持久層。瀏覽器需要在硬碟上保存各種數據,例如 Cookie。新的 HTML 規範 (HTML5) 定義了“網頁資料庫”,這是一個完整(但輕巧)的瀏覽器內資料庫。
值得注意的是,和大多數瀏覽器不同,Chrome 瀏覽器的每個標籤頁都分別對應一個呈現引擎實例。每個標籤頁都是一個獨立的進程。
二、主流程
呈現引擎一開始會從網路層取得請求文件的內容,內容的大小一般限制在 8000 個區塊以內。
接著進行如下所示的基本流程:
呈現引擎將開始解析HTML 文檔,並將各標記逐一轉換成「內容樹」上的DOM 節點。同時也會解析外部 CSS 檔案以及樣式元素中的樣式資料。 HTML 中這些帶有視覺指令的樣式資訊將用於建立另一個樹狀結構:呈現樹。
呈現樹包含多個帶有視覺屬性(如顏色和尺寸)的矩形。這些矩形的排列順序就是它們將在螢幕上顯示的順序。
呈現樹建構完畢之後,進入「佈局」處理階段,也就是為每個節點分配一個應出現在螢幕上的確切座標。下一個階段是繪製 - 呈現引擎會遍歷呈現樹,由使用者介面後端圖層將每個節點繪製出來。
需要著重指出的是,這是一個漸進的過程。 為達到更好的使用者體驗,呈現引擎會力求盡快將內容顯示在螢幕上。它不必等到整個 HTML 文件解析完畢之後,就會開始建立呈現樹和設定佈局。 在不斷接收和處理來自網路的其餘內容的同時,呈現引擎會將部分內容解析並顯示出來。
主流程範例:
1、腳本
#網路的模型是同步的。網頁作者希望解析器遇到 <script> 標記時立即解析並執行腳本。文件的解析將停止,直到腳本執行完畢。如果腳本是外部的,那麼解析過程就會停止,直到從網路同步抓取資源完成後再繼續。此模型已經使用了多年,也在 HTML4 和 HTML5 規範中進行了指定。作者也可以將腳本標註為“defer”,這樣它就不會停止文件解析,而是等到解析結束才執行。 HTML5 增加了一個選項,可將腳本標記為非同步,以便由其他執行緒解析和執行。 </script>
2、預解析
WebKit 和 Firefox 都進行了這項最佳化。 在執行腳本時,其他執行緒會解析文件的其餘部分,找出並載入需要透過網路載入的其他資源。透過這種方式,資源可以在並行連接上加載,從而提高整體速度。 請注意,預解析器不會修改 DOM 樹,而是將這項工作交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的參考。3、樣式表
另一方面,樣式表有著不同的模型。理論上來說,應用程式樣式表不會更改 DOM 樹,因此似乎沒有必要等待樣式表並停止文件解析。但這牽涉到一個問題,就是腳本在文件解析階段會要求樣式資訊。如果當時還沒有加載和解析樣式,腳本就會獲得錯誤的回复,這顯然會產生很多問題。這看起來是個非典型案例,但事實上非常普遍。 Firefox 在樣式表載入和解析的過程中,會禁止所有腳本。而對於 WebKit 而言,只有當腳本嘗試存取的樣式屬性可能受尚未載入的樣式表影響時,它才會禁止該腳本。4、呈現樹建構
在 DOM 樹建構的同時,瀏覽器也會建構另一個樹狀結構:呈現樹。這是由視覺化元素按照其顯示順序而組成的樹,也是文件的視覺化表示。它的作用是讓您按照正確的順序繪製內容。Firefox 將呈現樹中的元素稱為「框架」。 WebKit 使用的術語是呈現器或呈現物件。
呈現器知道如何佈局並將自身及其子元素繪製出來。
四、佈局
呈現器在建立完成並新增到呈現樹時,並不包含位置和大小資訊。計算這些值的過程稱為佈局或重排。
HTML 採用基於流的佈局模型,這意味著大多數情況下只要一次遍歷就能計算出幾何資訊。處於流中靠後位置元素通常不會影響前位置元素的幾何特徵,因此佈局可以按從左到右、從上至下的順序遍歷文件。但是也有例外情況,例如 HTML 表格的計算就需要不只一次的遍歷。
座標係是相對於根框架而建立的,使用的是上座標和左座標。
佈局是一個遞歸的過程。它從根呈現器(對應於 HTML 文件的 元素)開始,然後遞歸遍歷部分或所有的框架層次結構,為每一個需要計算的呈現器計算幾何資訊。
根呈現器的位置左邊是 0,0,其尺寸為視口(也就是瀏覽器視窗的可見區域)。
所有的呈現器都有一個「layout」或「reflow」方法,每個呈現器都會呼叫其需要進行佈局的子代的 layout 方法。
五、繪製
在繪製階段,系統會遍歷呈現樹,並呼叫呈現器的「paint」方法,將呈現器的內容顯示在螢幕上。繪製工作是使用使用者介面基礎元件完成的。
個人理解總結
一、解析器與預解析機制
呈現引擎從網路層取得請求文件的內容,然後開始解析HTML文件,並將各標記逐一轉化為DOM樹(內容樹)上的DOM 節點,同時也會解析外部CSS 文件以及樣式元素中的樣式資料。 HTML 中這些帶有視覺指令的樣式資訊將用於建立另一個樹狀結構:渲染樹(呈現樹)。呈現樹建構完畢之後,呈現引擎將對呈現樹進行佈局和繪製。
呈現引擎 的解析包括HTML 解析和CSS 解析,HTML 解析器的輸出「解析樹」是由DOM 元素和屬性節點構成的樹狀結構,DOM 是文件物件模型( Document Object Model) 的縮寫。它是 HTML 文件的物件表示,同時也是外部內容(例如 JavaScript)與 HTML 元素之間的介面。解析樹的根節點是「Document」物件。 CSS 解析器會將 CSS 樣式檔案和樣式元素中的樣式資料解析為 CSS 規則樹,瀏覽器結合 CSS 規則樹和 DOM 樹產生渲染樹。
JavaScript 解譯器 用來解析和執行 JavaScript 程式碼。
一般來講,我們認為瀏覽器從網絡層接收到HTML 文件內容,然後開始解析文檔生成DOM 樹,遇到CSS 樣式表標籤或JS 腳本標籤就起新線程去下載它們,並繼續建立DOM 樹,瀏覽器根據DOM 樹建立渲染樹,最後瀏覽器將渲染書繪製到使用者介面。
在上述描述中,需要著重指出的是,HTML 文件的解析和渲染是一個漸進的過程。為達到更好的使用者體驗,呈現引擎會力求盡快將內容顯示在螢幕上。它不必等到整個 HTML 文件解析完畢,就會開始建立呈現樹和設定佈局。在不斷接收和處理來自網路的其餘內容的同時,呈現引擎會將部分內容解析並顯示出來。
瀏覽器的預解析。 WebKit 和 Firefox 都進行了這項最佳化。在執行腳本時,其他執行緒會解析 HTML 文件的其餘部分,找出並載入需要透過網頁載入的其他資源。透過這種方式,資源可以在並行連接上加載,從而提高整體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工作交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的參考。
瀏覽器的預解析可以減緩渲染被阻塞的情況,例如在文件解析過程中預載器發現了<script src="last.js"></script>
標籤,會對last.js 檔案載入並放在瀏覽器快取中,這樣當解析器遇到這個<script> 標記時,由於預載器已經將last.js 檔案載入了,所以last.js 會被立即執行,不需要等待從網路抓取資源,減緩了對渲染的阻塞。 </script>
二、CSS 和 JS 的處理順序和阻塞分析
HTML 文件的解析和渲染過程中,外部樣式表和腳本 順序執行、並發載入。
JS 腳本會阻塞HTML 文件的解析,包括DOM 樹的構建和渲染樹的構建;CSS 樣式表會阻塞渲染樹的構建,但DOM 樹依然繼續構建(除非遇到script 標籤且css文件此時仍未載入完成),但不會渲染繪製到頁面上。
在 HTML 文件的解析過程中,解析器遇到 <script> 標籤時會立即解析並執行腳本,HTML 文件的解析將被阻塞,直到腳本執行完畢。如果腳本是外部的,那麼解析過程會停止,直到從網路抓取資源並解析和執行完成後,再繼續解析後續內容。 </script>
理論上來說,應用程式樣式表不會更改 DOM 樹,因此似乎沒有必要等待樣式表並停止文件解析。但這牽涉到一個問題,就是腳本在文件解析階段會要求樣式資訊。如果當時還沒有加載和解析樣式,腳本就會獲得錯誤的回复,這顯然會產生很多問題。這看起來是個非典型案例,但事實上非常普遍。 Firefox 在樣式表載入和解析的過程中,會禁止所有腳本。而對於 WebKit 而言,只有當腳本嘗試存取的樣式屬性可能受尚未載入的樣式表影響時,它才會禁止該腳本。
但無論是哪種情況導致的阻塞,該載入的外部資源還是會加載,例如外部腳本、樣式表和圖片。 HTML 文件的解析可能會被阻塞,但外部資源的載入不會被阻塞。
CSS 外部樣式表的載入會阻塞外部腳本的執行,但不會阻塞外部腳本的載入。這一點可以透過 chrome 偵錯工具中的 Network - Waterfall 進行驗證,但需要注意 chrome 的並發連線數(同一網域)上限為 6 個。
由上面兩張截圖可以看到,jquery.min.js 腳本檔案與bootstrap.css 等樣式檔案並行加載,但由於chrome 的並發連線數上限為6 個,因此bootstrap.min.js 腳本、xxx.css 樣式等檔案的載入會等待前面的檔案載入完成,有可用連線數的時候才開始載入。
了解以上資訊之後,我們可以對該頁面進行相應優化,例如對CSS檔案進行壓縮處理、使用CDN,將資源分佈在多個網域下、合併CSS 文件,減少HTTP 請求數量等,來提高CSS 的載入速度,減少HTML 文件解析和渲染的阻塞時間。
browser only allows six TCP connections per origin on HTTP 1.
瀏覽器的並發請求數目限制是針對相同網域的。因此可以使用 CDN 加速技術來提高使用者造訪網站的回應速度,這樣使用了 CDN 的資源載入不會佔用目前網域下的並發連線數,從而減少阻塞的時間。
網頁效能
了解 HTML 文件的解析和渲染的過程對於分析網頁效能有著重要意義,它可以幫助我們找到影響網頁效能的關鍵因素。例如,我們知道JS 外部腳本的執行會阻塞文件的解析,那麼重量級的第三方外掛程式會影響首頁載入的速度,如果因此影響到了使用者體驗,我們就需要考慮這個第三方外掛程式的使用成本是不是太高了,能否使用其他輕量級的插件進行替代,或只使用其中一部分模組。
以Datatables 為例:
上圖是一個專案頁面的Network 截圖,紅色框中的部分出現了約700ms 左右的空白,我們需要知道為什麼頁面的載入會出現這樣的情況,這段空白時間瀏覽器在做什麼?
我們分析 Timeline 圖,看看瀏覽器在這段時間的具體信息,如下:
透過Timeline 圖我們可以看到,在250ms~900ms 時間區間內,瀏覽器在執行datatables.min.js 腳本程式碼,這個腳本的執行阻塞了文件的解析,耗時約700ms,對應了Network 圖中的空白。
我們繼續查看頁面總的耗時時間,評估700ms 耗時的影響,如下:
可以看到,頁面總的完成耗時為1.66s,由此可知datatables.min.js 的執行耗時佔了很大比重,應當慎重考慮是否一定要使用這個插件,能否使用其他輕量級的插件進行替代,或者能否精簡插件的不必要模組,或捨棄插件的使用。
參考資料-1
瀏覽器接收到html程式碼,可能是一份完整的文檔,也可能是個chunk,也就是開始解析。解析過程是先建立dom樹,再根據dom樹建立渲染樹,最後瀏覽器將渲染樹繪製到頁面上。
構建dom樹的過程即根據html程式碼自上而下進行構建,當遇到script文件加載/執行會阻塞後面dom樹的構建(javascript可能會改變dom樹),而遇到css文件則會阻塞渲染樹的構建,即dom樹依然繼續構建(除非遇到script標籤並且css文件依舊未加載完成),但不會渲染繪製到頁面上。而無論哪個阻塞,該載入的文件還是會加載,例如html文件中的其他css/js/圖片檔。
另外javascript被載入後就會執行,執行的過程也會阻塞樹的建置。是執行完了才解析其他內容,而不是執行完了才載入其他內容。
作者:加冰
連結:https://www.zhihu.com/questio...
參考資料-2##首先,開源瀏覽器一般以8k每塊下載html頁面。
接著解析頁面產生DOM樹,遇到css標籤或JS腳本標籤就新起線程去下載他們,並繼續建構DOM。
下載完後解析CSS為CSS規則樹,瀏覽器結合CSS規則樹和DOM樹產生Render Tree。
注意:建置CSS Object Model(CSSOM)會阻塞JavaScript的執行。 JavaScript的執行也會阻塞DOM的建置。
JavaScript下載後可以透過DOM API修改DOM,透過CSSOM API修改樣式作用域Render Tree。
每次修改都會造成Render Tree的重新佈局和重繪。只要修改DOM或修改了元素的形狀或大小,就會觸發Reflow,單純修改元素的顏色只需Repaint一下(呼叫作業系統Native GUI的API繪製)。
連結:https://www.zhihu.com/questio...
JavaScript影片教學專欄!
#
以上是瀏覽器解析渲染HTML文件的過程詳解(圖文)的詳細內容。更多資訊請關注PHP中文網其他相關文章!