【浏览器渲染原理】步骤及优化
【瀏覽器渲染原理】步驟及優(yōu)化
文章目錄
- 【瀏覽器渲染原理】步驟及優(yōu)化
- 一、對瀏覽器內(nèi)核的理解
- 二、瀏覽器的主要組成部分
- 三、瀏覽器的渲染過程
- 四、瀏覽器渲染優(yōu)化
- ① 針對JavaScript:
- ② 針對CSS:
- ③ 針對DOM樹、CSSOM樹:
- ④ 減少回流與重繪:
- 五、渲染過程中遇到 JS 文件如何處理?
- 六、什么是文檔的預(yù)解析?
- 七、CSS 如何阻塞文檔解析?
- 八、如何優(yōu)化關(guān)鍵渲染路徑?
- 九、什么情況會阻塞渲染?
- 十、回流與重繪
- ① 回流與重繪的概念及觸發(fā)條件
- (1)回流(重排)
- (2)重繪
- ② 如何避免回流與重繪?
- ③ 如何優(yōu)化動畫?
- 十一、style樣式的渲染
- 十二、link引入
一、對瀏覽器內(nèi)核的理解
瀏覽器內(nèi)核主要分成兩部分:
- 渲染引擎的職責(zé)就是渲染,即在瀏覽器窗口中顯示所請求的內(nèi)容。默認(rèn)情況下,渲染引擎可以顯示 html、xml 文檔及圖片,它也可以借助插件顯示其他類型數(shù)據(jù),例如使用 PDF 閱讀器插件,可以顯示 PDF 格式。
- JS 引擎:解析和執(zhí)行 javascript 來實(shí)現(xiàn)網(wǎng)頁的動態(tài)效果。
最開始渲染引擎和 JS 引擎并沒有區(qū)分的很明確,后來 JS 引擎越來越獨(dú)立,內(nèi)核就傾向于只指渲染引擎。
二、瀏覽器的主要組成部分
- ?戶界? - 包括地址欄、前進(jìn)/后退按鈕、書簽菜單等。除了瀏覽器主窗?顯示的您請求的??外,其他顯示的各個部分都屬于?戶界?。
- 瀏覽器引擎 - 在?戶界?和呈現(xiàn)引擎之間傳送指令。
- 呈現(xiàn)引擎 - 負(fù)責(zé)顯示請求的內(nèi)容。如果請求的內(nèi)容是 HTML,它就負(fù)責(zé)解析 HTML 和 CSS 內(nèi)容,并將解析后的內(nèi)容顯示在屏幕上。
- ?絡(luò) - ?于?絡(luò)調(diào)?,?如 HTTP 請求。其接?與平臺?關(guān),并為所有平臺提供底層實(shí)現(xiàn)。
- ?戶界?后端 - ?于繪制基本的窗??部件,?如組合框和窗?。其公開了與平臺?關(guān)的通?接?,?在底層使?操作系統(tǒng)的?戶界??法。
- JavaScript 解釋器。?于解析和執(zhí)? JavaScript 代碼。
- 數(shù)據(jù)存儲 - 這是持久層。瀏覽器需要在硬盤上保存各種數(shù)據(jù),例如 Cookie。新的 HTML 規(guī)范 (HTML5) 定義了“?絡(luò)數(shù)據(jù)庫”,這是?個完整(但是輕便)的瀏覽器內(nèi)數(shù)據(jù)庫。
值得注意的是,和?多數(shù)瀏覽器不同,Chrome 瀏覽器的每個標(biāo)簽?都分別對應(yīng)?個呈現(xiàn)引擎實(shí)例。每個標(biāo)簽?都是?個獨(dú)?的進(jìn)程。
三、瀏覽器的渲染過程
解析: 瀏覽器讀取的代碼的過程,就是解析。
渲染: 渲染完畢之后,用戶就能看見對應(yīng)的東西
一個渲染引擎主要包括:HTML解釋器,css解析器,JavaScript引擎,布局Layout模塊,繪圖模塊
- HTML解析器 : 解析HTML文檔的解析,主要作用是將HTML文本解析為DM樹。
- CSS解析器: 它的作業(yè)是為DOM中的各個元素對象計算出樣式信息,為布局提供基礎(chǔ)設(shè)施
- JavaScript引擎: 使用JavaScript代碼可以修改網(wǎng)頁的內(nèi)容,也能修改css的信息,JavaScript引擎能夠解釋JavaScript代碼,并通過DOM接口操作頁面。
- 布局(Layout):在DOM創(chuàng)建之后,需要將其中的元素對象同樣式信息結(jié)合起來,計算他們的大小位置等布局信息。
- 繪圖模塊(paint):使用圖形庫將布局計算后的各個網(wǎng)頁的節(jié)點(diǎn)繪制層圖像結(jié)構(gòu)。
點(diǎn)擊這里👉
大致過程如圖所示:
注意:這個過程是逐步完成的,為了更好的用戶體驗(yàn),渲染引擎將會盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會等到所有的html 都解析完成之后再去構(gòu)建和布局 render 樹。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容,同時,可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容。
四、瀏覽器渲染優(yōu)化
① 針對JavaScript:
JavaScript既會阻塞HTML的解析,也會阻塞CSS的解析。因此我們可以對JavaScript的加載方式進(jìn)行改變,來進(jìn)行優(yōu)化:
(1)盡量將JavaScript文件放在body的最后
(2) body中間盡量不要寫<script>標(biāo)簽
(3)<script>標(biāo)簽的引入資源方式有三種,有一種就是我們常用的直接引入,還有兩種就是使用 async 屬性和 defer 屬性來異步引入,兩者都是去異步加載外部的JS文件,不會阻塞DOM的解析(盡量使用異步加載)。三者的區(qū)別如下:
- script 立即停止頁面渲染去加載資源文件,當(dāng)資源加載完畢后立即執(zhí)行js代碼,js代碼執(zhí)行完畢后繼續(xù)渲染頁面;
- async 是在下載完成之后,立即異步加載,加載好后立即執(zhí)行,多個帶async屬性的標(biāo)簽,不能保證加載的順序;
? <script async src="script.js"></script>
- defer 是在下載完成之后,立即異步加載。加載好后,如果 DOM 樹還沒構(gòu)建好,則先等 DOM 樹解析好再執(zhí)行;如果DOM樹已經(jīng)準(zhǔn)備好,則立即執(zhí)行。多個帶defer屬性的標(biāo)簽,按照順序執(zhí)行。
② 針對CSS:
使用CSS有三種方式:使用link、@import、內(nèi)聯(lián)樣式,其中l(wèi)ink和@import都是導(dǎo)入外部樣式。它們之間的區(qū)別:
- link:瀏覽器會派發(fā)一個新等線程(HTTP線程)去加載資源文件,與此同時GUI渲染線程會繼續(xù)向下渲染代碼
- @import:GUI渲染線程會暫時停止渲染,去服務(wù)器加載資源文件,資源文件沒有返回之前不會繼續(xù)渲染(阻礙瀏覽器渲染)
- style:GUI直接渲染
外部樣式如果長時間沒有加載完畢,瀏覽器為了用戶體驗(yàn),會使用瀏覽器會默認(rèn)樣式,確保首次渲染的速度。所以CSS一般寫在headr中,讓瀏覽器盡快發(fā)送請求去獲取css樣式。
所以,在開發(fā)過程中,導(dǎo)入外部樣式使用link,而不用@import。如果css少,盡可能采用內(nèi)嵌樣式,直接寫在style標(biāo)簽中。
③ 針對DOM樹、CSSOM樹:
可以通過以下幾種方式來減少渲染的時間:
- HTML文件的代碼層級盡量不要太深
- 使用語義化的標(biāo)簽,來避免不標(biāo)準(zhǔn)語義化的特殊處理
- 減少CSSD代碼的層級,因?yàn)檫x擇器是從左向右進(jìn)行解析的
④ 減少回流與重繪:
- 操作DOM時,盡量在低層級的DOM節(jié)點(diǎn)進(jìn)行操作
- 不要使用table布局, 一個小的改動可能會使整個table進(jìn)行重新布局
- 使用CSS的表達(dá)式
- 不要頻繁操作元素的樣式,對于靜態(tài)頁面,可以修改類名,而不是樣式。
- 使用absolute或者fixed,使元素脫離文檔流,這樣他們發(fā)生變化就不會影響其他元素
- 避免頻繁操作DOM,可以創(chuàng)建一個文檔片段documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中
- 將元素先設(shè)置display: none,操作結(jié)束后再把它顯示出來。因?yàn)樵赿isplay屬性為none的元素上進(jìn)行的DOM操作不會引發(fā)回流和重繪。
- 將DOM的多個讀操作(或者寫操作)放在一起,而不是讀寫操作穿插著寫。這得益于瀏覽器的渲染隊(duì)列機(jī)制。
瀏覽器針對頁面的回流與重繪,進(jìn)行了自身的優(yōu)化——渲染隊(duì)列
瀏覽器會將所有的回流、重繪的操作放在一個隊(duì)列中,當(dāng)隊(duì)列中的操作到了一定的數(shù)量或者到了一定的時間間隔,瀏覽器就會對隊(duì)列進(jìn)行批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。
將多個讀操作(或者寫操作)放在一起,就會等所有的讀操作進(jìn)入隊(duì)列之后執(zhí)行,這樣,原本應(yīng)該是觸發(fā)多次回流,變成了只觸發(fā)一次回流。
五、渲染過程中遇到 JS 文件如何處理?
JavaScript 的加載、解析與執(zhí)行會阻塞文檔的解析,也就是說,在構(gòu)建 DOM 時,HTML 解析器若遇到了 JavaScript,那么它會暫停文檔的解析,將控制權(quán)移交給 JavaScript 引擎,等 JavaScript 引擎運(yùn)行完畢,瀏覽器再從中斷的地方恢復(fù)繼續(xù)解析文檔。也就是說,如果想要首屏渲染的越快,就越不應(yīng)該在首屏就加載 JS 文件,這也是都建議將 script 標(biāo)簽放在 body 標(biāo)簽底部的原因。當(dāng)然在當(dāng)下,并不是說 script 標(biāo)簽必須放在底部,因?yàn)槟憧梢越o script 標(biāo)簽添加 defer 或者 async 屬性。
- css的解析和JS的執(zhí)行都互斥的,css解析的時候js停止執(zhí)行,js執(zhí)行的時候css停止解析。
- 無論css阻塞,或js阻塞,都不會阻塞瀏覽器加載外部資源(圖片,視頻,樣式,腳本)。
因?yàn)闉g覽始終處于一種“先把請求發(fā)送出去”的工作模式,只要涉及到網(wǎng)絡(luò)請求的內(nèi)容,無論是:圖片,樣式,腳本,都會先發(fā)送請求去獲取資源,至于資源到本地之后什么時候用,由瀏覽器自己去協(xié)調(diào)。
- 阻塞瀏覽器渲染
- 阻塞DOM解析
- 阻塞JS執(zhí)行
六、什么是文檔的預(yù)解析?
Webkit 和 Firefox 都做了這個優(yōu)化,當(dāng)執(zhí)行 JavaScript 腳本時,另一個線程解析剩下的文檔,并加載后面需要通過網(wǎng)絡(luò)加載的資源。這種方式可以使資源并行加載從而使整體速度更快。需要注意的是,預(yù)解析并不改變 DOM 樹,它將這個工作留給主解析過程,自己只解析外部資源的引用,比如外部腳本、樣式表及圖片。
七、CSS 如何阻塞文檔解析?
理論上,既然樣式表不改變 DOM 樹,也就沒有必要停下文檔的解析等待它們。然而,存在一個問題,JavaScript 腳本執(zhí)行時可能在文檔的解析過程中請求樣式信息,如果樣式還沒有加載和解析,腳本將得到錯誤的值,顯然這將會導(dǎo)致很多問題。所以如果瀏覽器尚未完成 CSSOM 的下載和構(gòu)建,而我們卻想在此時運(yùn)行腳本,那么瀏覽器將延遲 JavaScript 腳本執(zhí)行和文檔的解析,直至其完成 CSSOM 的下載和構(gòu)建。也就是說,在這種情況下,瀏覽器會先下載和構(gòu)建 CSSOM,然后再執(zhí)行 JavaScript,最后再繼續(xù)文檔的解析。
八、如何優(yōu)化關(guān)鍵渲染路徑?
什么是關(guān)鍵渲染路徑:
瀏覽器將HTML,CSS,JavaScript到首次渲染到屏幕上(首屏),這期間所經(jīng)歷的一系列步驟,叫做關(guān)鍵渲染路徑(Critical Rendering Path)。
可見,通過優(yōu)化關(guān)鍵渲染路徑,我們可以顯著縮短首次渲染頁面的時間,從而得到一個更好的用戶體驗(yàn)。
什么是關(guān)鍵資源:
關(guān)鍵資源指的是那些可以阻塞頁面首次渲染的資源。例如JavaScript、CSS都是可以阻塞關(guān)鍵渲染路徑的資源,這些資源就屬于關(guān)鍵資源。圖片不屬于關(guān)鍵資源, 因?yàn)閳D片不會導(dǎo)致阻塞游覽器渲染。
如何優(yōu)化關(guān)鍵渲染路徑:
為盡快完成首次渲染,我們需要最大限度減小以下三種可變因素:
(1)關(guān)鍵資源的數(shù)量。
(2)關(guān)鍵路徑長度。
(3)關(guān)鍵字節(jié)的數(shù)量。
關(guān)鍵資源是可能阻止網(wǎng)頁首次渲染的資源。這些資源越少,瀏覽器的工作量就越小,對 CPU 以及其他資源的占用也就越少。
關(guān)鍵資源的長度指的是獲取所有關(guān)鍵資源時,在瀏覽器與服務(wù)器之間的往返次數(shù)。
同樣,關(guān)鍵路徑長度受所有關(guān)鍵資源與其字節(jié)大小之間依賴關(guān)系圖的影響:某些資源只能在上一資源處理完畢之后才能開始下載,并且資源越大,下載所需的往返次數(shù)就越多。最后,瀏覽器需要下載的關(guān)鍵字節(jié)越少,處理內(nèi)容并讓其出現(xiàn)在屏幕上的速度就越快。
要減少字節(jié)數(shù),我們可以減少資源數(shù)(將它們刪除或設(shè)為非關(guān)鍵資源),此外還要壓縮和優(yōu)化各項(xiàng)資源,確保最大限度減小傳送大小。
優(yōu)化關(guān)鍵渲染路徑的常規(guī)步驟如下:
(1)對關(guān)鍵路徑進(jìn)行分析和特性描述:資源數(shù)、字節(jié)數(shù)、長度。
(2)最大限度減少關(guān)鍵資源的數(shù)量:刪除它們,延遲它們的下載,將它們標(biāo)記為異步等。
(3)優(yōu)化關(guān)鍵字節(jié)數(shù)以縮短下載時間(往返次數(shù))。
(4)優(yōu)化其余關(guān)鍵資源的加載順序:您需要盡早下載所有關(guān)鍵資產(chǎn),以縮短關(guān)鍵路徑長度
九、什么情況會阻塞渲染?
首先渲染的前提是生成渲染樹,所以 HTML 和 CSS 肯定會阻塞渲染。如果你想渲染的越快,你越應(yīng)該降低一開始需要渲染的文件大小,并且扁平層級,優(yōu)化選擇器。然后當(dāng)瀏覽器在解析到 script 標(biāo)簽時,會暫停構(gòu)建 DOM,完成后才會從暫停的地方重新開始。也就是說,如果你想首屏渲染的越快,就越不應(yīng)該在首屏就加載 JS 文件,這也是都建議將 script 標(biāo)簽放在 body 標(biāo)簽底部的原因。
當(dāng)然在當(dāng)下,并不是說 script 標(biāo)簽必須放在底部,因?yàn)槟憧梢越o script 標(biāo)簽添加 defer 或者 async 屬性。當(dāng) script 標(biāo)簽加上 defer 屬性以后,表示該 JS 文件會并行下載,但是會放到 HTML 解析完成后順序執(zhí)行,所以對于這種情況你可以把 script 標(biāo)簽放在任意位置。對于沒有任何依賴的 JS 文件可以加上 async 屬性,表示 JS 文件下載和解析不會阻塞渲染。
十、回流與重繪
① 回流與重繪的概念及觸發(fā)條件
(1)回流(重排)
當(dāng)渲染樹中部分或者全部元素的尺寸、結(jié)構(gòu)或者屬性發(fā)生變化時,瀏覽器會重新渲染部分或者全部文檔的過程就稱為回流。
下面這些操作會導(dǎo)致回流:
- 頁面的首次渲染
- 瀏覽器的窗口大小發(fā)生變化
- 元素的內(nèi)容發(fā)生變化
- 元素的尺寸或者位置發(fā)生變化
- 元素的字體大小發(fā)生變化
- 激活CSS偽類
- 查詢某些屬性或者調(diào)用某些方法
- 添加或者刪除可見的DOM元素
在觸發(fā)回流(重排)的時候,由于瀏覽器渲染頁面是基于流式布局的,所以當(dāng)觸發(fā)回流時,會導(dǎo)致周圍的DOM元素重新排列,它的影響范圍有兩種:
- 全局范圍:從根節(jié)點(diǎn)開始,對整個渲染樹進(jìn)行重新布局
- 局部范圍:對渲染樹的某部分或者一個渲染對象進(jìn)行重新布局
(2)重繪
當(dāng)頁面中某些元素的樣式發(fā)生變化,但是不會影響其在文檔流中的位置時,瀏覽器就會對元素進(jìn)行重新繪制,這個過程就是重繪。
下面這些操作會導(dǎo)致回流:
- color、background 相關(guān)屬性:background-color、background-image 等
- outline 相關(guān)屬性:outline-color、outline-width 、text-decoration
- border-radius、visibility、box-shadow
注意: 當(dāng)觸發(fā)回流時,一定會觸發(fā)重繪,但是重繪不一定會引發(fā)回流。
② 如何避免回流與重繪?
減少回流與重繪的措施:
- 操作DOM時,盡量在低層級的DOM節(jié)點(diǎn)進(jìn)行操作
- 不要使用table布局, 一個小的改動可能會使整個table進(jìn)行重新布局
- 使用CSS的表達(dá)式
- 不要頻繁操作元素的樣式,對于靜態(tài)頁面,可以修改類名,而不是樣式。
- 使用absolute或者fixed,使元素脫離文檔流,這樣他們發(fā)生變化就不會影響其他元素
- 避免頻繁操作DOM,可以創(chuàng)建一個文檔片段documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中
- 將元素先設(shè)置display: none,操作結(jié)束后再把它顯示出來。因?yàn)樵赿isplay屬性為none的元素上進(jìn)行的DOM操作不會引發(fā)回流和重繪。
- 將DOM的多個讀操作(或者寫操作)放在一起,而不是讀寫操作穿插著寫。這得益于瀏覽器的渲染隊(duì)列機(jī)制。
瀏覽器針對頁面的回流與重繪,進(jìn)行了自身的優(yōu)化——渲染隊(duì)列
瀏覽器會將所有的回流、重繪的操作放在一個隊(duì)列中,當(dāng)隊(duì)列中的操作到了一定的數(shù)量或者到了一定的時間間隔,瀏覽器就會對隊(duì)列進(jìn)行批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。
上面,將多個讀操作(或者寫操作)放在一起,就會等所有的讀操作進(jìn)入隊(duì)列之后執(zhí)行,這樣,原本應(yīng)該是觸發(fā)多次回流,變成了只觸發(fā)一次回流。
③ 如何優(yōu)化動畫?
對于如何優(yōu)化動畫,我們知道,一般情況下,動畫需要頻繁的操作DOM,就就會導(dǎo)致頁面的性能問題,我們可以將動畫的position屬性設(shè)置為absolute或者fixed,將動畫脫離文檔流,這樣他的回流就不會影響到頁面了。
十一、style樣式的渲染
style標(biāo)簽中的樣式由html解析器進(jìn)行解析
style 標(biāo)簽里的樣式是異步解析的,容易產(chǎn)生“閃屏”現(xiàn)象,瀏覽器加載資源是異步的,邊加載邊渲染
1、style標(biāo)簽不會阻止DOM的解析,但是會阻止頁面的渲染
2、遇到耗時任務(wù),style標(biāo)簽內(nèi)容過多,再開啟一個html解析器進(jìn)行解析。
Tips: style中的樣式不解析完畢,頁面不會渲染。
style:內(nèi)聯(lián)
一進(jìn)頁面,就看見最初的樣子,所有的加載過程都可以看見(過程都看出來)
十二、link引入
link:瀏覽器會派發(fā)一個新等線程(HTTP線程)去加載資源文件,與此同時GUI渲染線程會繼續(xù)向下渲染代碼
1、遇到link,使用css解析器解析異步解析,接著解析下面的html。
2、等待圖片和樣式都加載完畢,計算樣式,繪制頁面。只有css解析完成工作才會繪制頁面。
3、遇到link,使用css解析器解析異步解析,接著解析下面的html。
通過link引入,樣式解析,計算都會造成阻塞。
總結(jié)
1、link進(jìn)來的樣式,由css解析器去解析,并且是同步解析的。
2、css解析器會阻塞頁面的渲染。(link引入的外部樣式會阻塞頁面渲染),不會阻塞DOM解析
3、推薦使用link引入樣式。
link:外鏈
一進(jìn)頁面先空白,因?yàn)檫@個時候在請求資源、解析,等著 Stylesheet 解析完了,統(tǒng)一渲染,只看見最終結(jié)果
所以我們一般用 link 外鏈,只向用戶顯示最終結(jié)果
總結(jié)
以上是生活随笔為你收集整理的【浏览器渲染原理】步骤及优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于YOLOv5的PCB板缺陷检测
- 下一篇: 前端:页面快速定位和返回顶部(锚点)