前端面試題之渲染原理


瀏覽器的內核是指支持瀏覽器運行的最核心的程序,分為JS引擎和渲染引擎兩個部分。

頁面加載完成的過程

在網頁的地址欄中輸入url后,瀏覽器經歷了什么樣的過程?

  • 客戶端根據DNS服務器得到域名對應的ip地址;
  • 客戶端向該ip地址發送http請求;
  • 服務器端收到、處理並返回http請求;
  • 客戶端收到響應並返回內容。
  • 客戶端渲染

瀏覽器收到的其實就是HTML文件,只有HTML格式瀏覽器才能正確解析。接下來就是瀏覽器的渲染過程。

頁面渲染過程

HTML渲染過程主要分為以下部分:

1、解析HTML,生成DOM樹;

2、解析CSS,生成CSS規則樹;

3、合並DOM樹和CSS規則樹,生成render樹;

4、布局render樹(layout/reflow);

5、繪制render樹(print),繪制頁面像素信息;

6、瀏覽器將各層的信息發送給GUI,GUI將各層合成,顯示在屏幕上。

構建DOM樹

瀏覽器根據一定的規則將HTML轉換為DOM樹,大致可以分為幾個步驟:

  • 網絡中傳輸的內容其實是01這種字節數據,瀏覽器在收到字節數據后,才將字節數據轉換為字符串
  • 當數據轉換為字符串以后,瀏覽器會先將這些字符串通過詞法分析轉換為標記(token),這一過程叫做標記化。Token中會標識出當前Token是“開始標簽”還是“結束標簽”亦或是“文本”等信息。
  • 結束化結束之后,這些標記緊接着就會被轉換為Node,這些Node會根據不同Node之前的聯系生成DOM樹(Document Object Model)。

除了HTML文件還有CSS文件和JS文件。

構建CSSOM樹

構建CSSOM樹(CSS Object Model)的過程與構建DOM樹是極其相似的。

在這個過程中,瀏覽器會確定下一個節點的樣式,並且這個過程是非常消耗資源的。因為節點的樣式可以直接設置,也可以通過繼承獲得,瀏覽器必須遞歸CSSOM樹才能確定具體的元素的樣式。

構建渲染樹

當生成DOM樹和CSSOM樹之后,下一步就是將這兩棵樹組合為渲染樹

構建渲染樹並不是簡單的將兩棵樹合並起來。渲染樹只會包括需要顯示的節點和這些節點的樣式信息,如果某個節點是display: none的樣式,那就不會構建到渲染樹中。

那么,瀏覽器在渲染過程中遇到JS文件會怎么處理?

在渲染過程中,如果遇到<script>停止渲染,執行JS代碼。因為瀏覽器有GUI渲染線程和JS引擎線程,這兩個線程是互斥的,JavaScript的加載、解析和執行會阻塞渲染

面試題:“為什么大家普遍把<script scr=""></script>這樣的代碼放在body最底部?

JS文件不止會阻塞DOM的構建,也會導致CSSOM的構建。不完整的CSSOM是無法使用的,JavaScript想要訪問CSSOM並更改它,就必須得到完整的CSSOM。所以導致瀏覽器在未完成CSSOM的構建的時候想要運行JavaScript。這種情況下,瀏覽器會先下載和構建CSSOM,然后再執行JavaScript。

<script>標簽必須放在底部嗎?

並不是必須放在底部,我們可以為script標簽添加屬性:

  • defer屬性,表示js文件會並行下載,但是會放到HTML解析完成后順序執行。
  • async屬性,對於沒有任何依賴的js文件可以使用,表示JS文件下載和解析不會阻塞渲染。

async與defer的區別在於,如果已經加載好,就會開始執行,即使仍在HTML解析階段,所以這種方式加載的JavaScript依然會阻塞load事件。

async-scrapt可能在DOMContentLoaded觸發直線或之后執行,但一定在load之前執行,所以多個async-script的執行順序是不確定的。

布局和繪制

在這個過程中,瀏覽器要弄清楚各個節點在頁面中的確切位置和大小,通常這一行為也被成為自動重排

布局流程的輸出是一個“盒模型”,它會精確的捕獲每個元素在窗口的確切位置和大小,所有相對測量值,都會轉換為絕對值。

布局完成后,瀏覽器立即發出“Print Setup”和“Paint”事件,將渲染樹轉換成屏幕上的元素。

重繪(Repaint)和回流(reflow)

  • 重繪是當前節點需要更改外觀而不會影響布局的,比如改變color屬性。
  • 回流是布局或者幾何屬性需要改變

回流必定發生重繪,重繪不一定發生回流。回流所需要的成本遠大於重繪,因為回流很可能會導致跟該節點相關的很多節點的回流。

會導致性能問題的操作:

  • 改變window大小
  • 改變字體
  • 添加和刪除樣式
  • 文字改動
  • 定位或者浮動
  • 盒模型

因為很多操作都會消耗GPU,所以我們需要規避一些操作減少重繪和回流的次數:

  • 使用transfrom代替top
  • 使用visibility代替display: none(前者引起重繪,后者引起回流)
  • 不要把節點的屬性值放在一個循環里當成循環的變量
  • 不要使用table布局(小改動可能造成整個table重新布局)
  • CSS選擇符從右往左匹配查找,避免節點層級過多
  • 動畫實現的速度的選擇,動畫速度越快,回流次數越多,或者選擇使用requestAnimationFrame
  • 將頻繁重繪或回流的節點設置為圖層,圖層能夠阻止該節點影響到別的節點。

總結

知道了這么多東西,我們會選擇一些優化策略:

1、從文件大小考慮

2、將css放在頭部,將js放在尾部

3、減少資源請求數量

4、下載的內容是否要在首屏上使用

5、script標簽的使用加defer或async屬性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM