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