您好,登錄后才能下訂單哦!
小編給大家分享一下瀏覽器解析渲染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 增加了一個選項,可將腳本標記為異步,以便由其他線程解析和執行。
2、預解析
WebKit 和 Firefox 都進行了這項優化。在執行腳本時,其他線程會解析文檔的其余部分,找出并加載需要通過網絡加載的其他資源。通過這種方式,資源可以在并行連接上加載,從而提高總體速度。請注意,預解析器不會修改 DOM 樹,而是將這項工作交由主解析器處理;預解析器只會解析外部資源(例如外部腳本、樣式表和圖片)的引用。
3、樣式表
另一方面,樣式表有著不同的模型。理論上來說,應用樣式表不會更改 DOM 樹,因此似乎沒有必要等待樣式表并停止文檔解析。但這涉及到一個問題,就是腳本在文檔解析階段會請求樣式信息。如果當時還沒有加載和解析樣式,腳本就會獲得錯誤的回復,這樣顯然會產生很多問題。這看上去是一個非典型案例,但事實上非常普遍。Firefox 在樣式表加載和解析的過程中,會禁止所有腳本。而對于 WebKit 而言,僅當腳本嘗試訪問的樣式屬性可能受尚未加載的樣式表影響時,它才會禁止該腳本。
4、呈現樹構建
在 DOM 樹構建的同時,瀏覽器還會構建另一個樹結構:呈現樹。這是由可視化元素按照其顯示順序而組成的樹,也是文檔的可視化表示。它的作用是讓您按照正確的順序繪制內容。
Firefox 將呈現樹中的元素稱為“框架”。WebKit 使用的術語是呈現器或呈現對象。
呈現器知道如何布局并將自身及其子元素繪制出來。
四、布局
呈現器在創建完成并添加到呈現樹時,并不包含位置和大小信息。計算這些值的過程稱為布局或重排。
HTML 采用基于流的布局模型,這意味著大多數情況下只要一次遍歷就能計算出幾何信息。處于流中靠后位置元素通常不會影響靠前位置元素的幾何特征,因此布局可以按從左至右、從上至下的順序遍歷文檔。但是也有例外情況,比如 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 會被立即執行,不需要等待從網絡抓取資源,減緩了對渲染的阻塞。
二、CSS 和 JS 的處理順序和阻塞分析
HTML 文檔的解析和渲染過程中,外部樣式表和腳本 順序執行、并發加載。
JS 腳本會阻塞 HTML 文檔的解析,包括 DOM 樹的構建和渲染樹的構建;CSS 樣式表會阻塞渲染樹的構建,但 DOM 樹依然繼續構建(除非遇到 script 標簽且 css 文件此時仍未加載完成),但不會渲染繪制到頁面上。
在 HTML 文檔的解析過程中,解析器遇到 <script> 標記時會立即解析并執行腳本,HTML 文檔的解析將被阻塞,直到腳本執行完畢。如果腳本是外部的,那么解析過程會停止,直到從網絡抓取資源并解析和執行完成后,再繼續解析后續內容。
理論上來說,應用樣式表不會更改 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繪制)。
看完了這篇文章,相信你對瀏覽器解析渲染HTML文檔的過程是什么有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。