浏览器渲染原理-通俗易懂版本
生活随笔
收集整理的這篇文章主要介紹了
浏览器渲染原理-通俗易懂版本
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 瀏覽器渲染原理
- 前言
- 1. 網頁的解析過程
- 2. 瀏覽器的功能與組成
- 2.1 瀏覽器內核
- 2.2 進程與線程
- 3. 瀏覽器渲染流程
- 3.1 渲染引擎解析過程
- 3.2 渲染引擎主要模塊
- 4. 渲染頁面的詳細流程
- 4.1 HTML 解析過程
- 4.2 生成 CSS 規則
- 4.3 構建 Render Tree
- 4.4 布局 (layout) 和繪制 (Paint)
- 5. 重繪和回流解析
- 5.1 重繪(Repaint)
- 5.2 回流/重排(reflow)
- 5.3 常見的觸發"回流/重排"操作
- 5.4 合成和性能優化
- 5.5 script 元素和頁面解析的關系
- 6. defer 和 async 屬性
- 6.1 defer 屬性
- 6.2 async 屬性
瀏覽器渲染原理
前言
瀏覽器的主要功能總結起來就是一句話:將用戶輸入的 URL 轉變成可視化的圖像。
1. 網頁的解析過程
- 思考一下:一個網頁從 url 輸入到瀏覽器,經歷過怎樣的解析過程?
- 要想深入理解下載的過程,我們還要先理解,一個 index.html 被下載下來后是如何被解析和顯示在瀏覽器上的;
2. 瀏覽器的功能與組成
2.1 瀏覽器內核
瀏覽器的內核相當于汽車的發動機,是最核心的存在,它負責將代碼轉換成用戶眼中的界面。
- 我們經常說的瀏覽器內核指的是瀏覽器的排版引擎:
- 排版引擎 (layout engine),也稱為瀏覽器引擎 (browser engine)、頁面渲染引擎 (rendering engine) 或樣版引擎;
- 也就是一個網頁下載下來后,就是由我們的渲染引擎來幫助我們解析的;
2.2 進程與線程
- 進程與線程的解釋:
- 進程:程序的一次執行,它占有一片獨有的內存空間,是操作系統執行的基本單元;
- 線程:是進程內的一個獨立執行單元,是 CPU 調度的最小單元;
- 瀏覽器: 多進程、多線程模型
- Browser 進程:
- 瀏覽器的主進程,負責瀏覽器界面的顯示,和各個頁面的管理;
- 瀏覽器中所有其他類型進程的祖先,負責其他進程的的創建和銷毀,它有且只有一個!
- Renderer 進程:
- 網頁渲染進程,負責頁面的渲染,可以有多個渲染進程的數量,不一定是打開頁面的數量;
- GPU Process:負責 GPU 相關;
- Plugin Process:負責控制一個網頁用到的 Plugin;
- Browser 進程:
3. 瀏覽器渲染流程
3.1 渲染引擎解析過程
- 渲染引擎在拿到一個頁面后,如何解析整個頁面并且最終呈現出我們的網頁呢?
- 我們通過下面的這幅圖,讓我們更加詳細的學習它的過程;
3.2 渲染引擎主要模塊
- 一個渲染引擎主要包括:HTML 解析器,CSS 解析器,javascript 引擎,布局 layout 模塊,繪圖模塊;
- HTML 解析器:解釋 HTML 文檔的解析器,主要作用是將 HTML 文本解釋成 DOM 樹;
- CSS 解析器:它的作用是為 DOM 中的各個元素對象計算出樣式信息,為布局提供基礎設施;
- Javascript 引擎:使用 Javascript 代碼可以修改網頁的內容,也能修改 css 的信息,javascript 引擎能夠解釋 javascript 代碼,并通過 DOM 接口和 CSS 樹接口來修改網頁內容和樣式信息,從而改變渲染的結果
- 布局 (layout):在 DOM 創建之后,Webkit 需要將其中的元素對象同樣式信息結合起來,計算他們的大小位置等布局信息,形成一個能表達這所有信息的內部表示模型
- 繪圖模塊 (paint):使用圖形庫將布局計算后的各個網頁的節點繪制成圖像結果
4. 渲染頁面的詳細流程
瀏覽器渲染頁面的整個過程:瀏覽器會從上到下解析文檔。
4.1 HTML 解析過程
遇見 HTML 標記,調用 HTML 解析器解析為對應的 token (一個 token 就是一個標簽文本的序列化)并構建 DOM 樹(就是一塊內存,保存著 tokens,建立它們之間的關系)
4.2 生成 CSS 規則
遇見 style/link 標記調用解析器處理 CSS 標記并構建 CSS 樣式樹。
4.3 構建 Render Tree
當有了 DOM Tree 和 CSSOM Tree 后,就可以兩個結合來構建 Render Tree 了
- 注意一: link 元素不會阻塞 DOM Tree 的構建過程,但是會阻塞 Render Tree 的構建過程
- 這是因為 Render Tree 在構建時,需要對應的 CSSOM Tree;
- 注意二: Render Tree 和 DOM Tree 并不是一一對應的關系
- 比如對于 display 為 none 的元素,壓根不會出現在 render tree 中;
4.4 布局 (layout) 和繪制 (Paint)
- 第四步是:在渲染樹(Render Tree)上運行布局(Layout) 來計算每個節點的幾何體。
- 渲染樹會表示顯示哪些節點以及其他樣式,但是不表示每個節點的尺寸、位置等信息;
- 布局是確定呈現樹中所有節點的寬度、高度和位置信息;
- 第五步是:將每個節點繪制(Paint)到屏幕上。
- 在繪制階段,瀏覽器將布局階段計算的每個 frame 轉為屏幕上實際的像素點;
- 包括將元素的可見部分進行繪制,比如文本、顏色、邊框、陰影、替換元素(比如 img)
5. 重繪和回流解析
5.1 重繪(Repaint)
- 第一次渲染內容稱之為繪制(paint)
- 之后重新渲染稱之為重繪
- 重繪不會帶來重新布局,所以并不一定伴隨重排。
- 瀏覽器會根據元素的新屬性重新繪制,使元素呈現新的外觀。
- 什么屬性會導致重繪呢?
- color background box-shadow.. (比如修改背景色、文字顏色、邊框顏色、樣式等)
5.2 回流/重排(reflow)
理解回流 reflow :也可以稱之為重排
- 第一次確定節點的大小和位置,稱之為布局(layout)
- 之后對節點的大小、位置修改重新計算稱之為回流
- “重排/回流"必然導致"重繪”
- 比如改變一個網頁元素的位置,就會同時觸發"重排"和"重繪",因為布局改變了
- 所以回流是一件很消耗性能的事情
- 什么屬性會導致回流呢?
- width top position.. (比如 DOM 結構發生改變 / 修改了布局)
5.3 常見的觸發"回流/重排"操作
- Reflow 的成本比 Repaint 的成本高得多的多。
- 所以在開發中要盡量避免發生回流:
- 修改樣式時盡量一次性修改
- 將多次改變樣式屬性的操作合并成一次操作
- 預先定義好 class,然后修改 DOM 的 className
- 盡量避免頻繁的操作 DOM
- 我們可以在一個 DocumentFragment 或者父元素中將要操作的 DOM 操作完成,再一次性的操作;
- 盡量避免通過 getComputedStyle 獲取尺寸、位置等信息;
- 對某些元素使用 position 的 absolute 或者 fixed
- 并不是不會引起回流,而是開銷相對較小,不會對其他元素造成影響。
5.4 合成和性能優化
- 繪制的過程,可以將布局后的元素繪制到多個合成圖層中
- 這是瀏覽器的一種優化手段
- 默認情況下,標準流中的內容都是被繪制在同一個圖層(Layer)中的
- 而一些特殊的屬性,會創建一個新的合成層( CompositingLayer ),并且新的圖層可以利用 GPU 來加速繪制
- 因為每個合成層都是單獨渲染的
- 那么哪些屬性可以形成新的合成層呢? 常見的一些屬性:
- 3D transforms
- video、 canvas、 iframe
- opacity 動畫轉換時
- position: fixed
- will-change:一個實驗性的屬性,提前告訴瀏覽器元素可能發生哪些變化
- animation 或 transition 設置了 opacity、 transform
- 分層確實可以提高性能,但是它以內存管理為代價,因此不應作為 web 性能優化策略的一部分過度使用
5.5 script 元素和頁面解析的關系
- 我們現在已經知道了頁面的渲染過程,但是 JavaScript 在哪里呢?
- 事實上,瀏覽器在解析 HTML 的過程中,遇到了 script 元素是不能繼續構建 DOM 樹的;
- 它會停止繼續構建,首先下載 JavaScript 代碼,并且執行 JavaScript 的腳本;
- 只有等到 JavaScript 腳本執行結束后,才會繼續解析 HTML,構建 DOM 樹;
- 為什么要這樣做呢?
- 這是因為 JavaScript 的作用之一就是操作 DOM,并且可以修改 DOM;
- 如果我們等到 DOM 樹構建完成并且渲染再執行 JavaScript,會造成嚴重的回流和重繪,影響頁面的性能;
- 所以會在遇到 script 元素時,優先下載和執行 JavaScript 代碼,再繼續構建 DOM 樹;
- 但是這個也往往會帶來新的問題,特別是現代頁面開發中:
- 在目前的開發模式中(比如 Vue、 React),腳本往往比 HTML 頁面更“重”,處理時間需要更長;
- 所以會造成頁面的解析阻塞,在腳本下載、執行完成之前,用戶在界面上什么都看不到;
- 為了解決這個問題, script 元素給我們提供了兩個屬性(attribute): defer 和 async。
6. defer 和 async 屬性
6.1 defer 屬性
- defer 屬性:告訴瀏覽器不要等待腳本下載,而繼續解析 HTML,構建 DOM Tree。
- 腳本會由瀏覽器來進行下載,但是不會阻塞 DOM Tree 的構建過程;
- 如果腳本提前下載好了,它會等待 DOM Tree 構建完成,在 DOMContentLoaded 事件之前先執行 defer 中的代碼;
- 所以 DOMContentLoaded 總是會等待 defer 中的代碼先執行完成。
- 另外多個帶 defer 的腳本是可以保持正確的順序執行的。
- 從某種角度來說, defer 可以提高頁面的性能,并且推薦放到 head 元素中;
- 注意: defer 僅適用于外部腳本,對于 script 默認內容會被忽略。
6.2 async 屬性
- sync 特性與 defer 有些類似,它也能夠讓腳本不阻塞頁面。
- async 是讓一個腳本完全獨立的:
- 瀏覽器不會因 async 腳本而阻塞(與 defer 類似);
- async 腳本不能保證順序,它是獨立下載、獨立運行,不會等待其他腳本;
- async 不會能保證在 DOMContentLoaded 之前或者之后執行
- defer 通常用于需要在文檔解析后操作 DOM 的 JavaScript 代碼,并且對多個 script 文件有順序要求的;
- async 通常用于獨立的腳本,對其他腳本,甚至 DOM 沒有依賴的;
總結
以上是生活随笔為你收集整理的浏览器渲染原理-通俗易懂版本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python决策树补全缺失信息
- 下一篇: 图解浏览器渲染原理及流程