网站性能优化--CRP
網(wǎng)站性能優(yōu)化–CRP
為了把HTML、CSS和JavaScript轉(zhuǎn)化成活靈活現(xiàn)、絢麗多彩的網(wǎng)頁(yè),瀏覽器需要處理一系列的中間過(guò)程,優(yōu)化性能其實(shí)就是了解這個(gè)過(guò)程中發(fā)生了什么-即CRP(Critical Rendering Path,關(guān)鍵渲染路徑)。首先,我們從頭開始快速學(xué)習(xí)一下瀏覽器是如何顯示一個(gè)簡(jiǎn)單網(wǎng)頁(yè)的。瀏覽器渲染一個(gè)網(wǎng)頁(yè)的過(guò)程
構(gòu)建對(duì)象模型
文檔對(duì)象模型(DOM)
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><link href="style.css" rel="stylesheet"><title>Critical Path</title></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div></body> </html>一個(gè)普通的頁(yè)面,里面包含一些文本和一張圖片,瀏覽器是如何處理這個(gè)頁(yè)面的呢?
上述整個(gè)流程的最終輸出是文檔對(duì)象模型,即這個(gè)簡(jiǎn)單網(wǎng)頁(yè)的 “DOM”,瀏覽器完成頁(yè)面的所有后續(xù)處理都是建立在這個(gè)DOM基礎(chǔ)上的。
打開Chrome DevTools > Timeline,錄制時(shí)間軸,上述過(guò)程對(duì)應(yīng)Loading事件中的Parse HTML事件,可以查看到執(zhí)行這一過(guò)程所需要的時(shí)間。
DOM樹捕獲了文檔標(biāo)記的屬性及關(guān)系,但它沒(méi)有告訴我們?cè)卦阡秩緯r(shí)是什么樣子的。這是CSSOM要干的活,也就是接下來(lái)要講的。
CSS對(duì)象模型(CSSOM)
當(dāng)瀏覽器構(gòu)建上述網(wǎng)頁(yè)DOM的時(shí)候,在head里面碰到一個(gè)link標(biāo)簽,這個(gè)標(biāo)簽引用了一個(gè)外部的CSS樣式表:style.css。瀏覽器預(yù)測(cè)會(huì)需要這個(gè)資源來(lái)渲染頁(yè)面,因此會(huì)立即發(fā)出一個(gè)該資源的請(qǐng)求,該請(qǐng)求返回以下內(nèi)容:
與HTML一樣,我們需要將收到的 CSS 規(guī)則轉(zhuǎn)換為瀏覽器可以理解、能夠處理的東西。因此,我們重復(fù)與處理 HTML 非常相似的過(guò)程:
最終輸出的是CSS對(duì)象模型,即CSSOM。
想要查看CSS處理過(guò)程所花費(fèi)的時(shí)間,可以在錄制的時(shí)間軸中查看Rendering事件中的Recalculate Style事件:與DOM解析不同,timeline不顯示單獨(dú)的“Parse CSS”條目,而是在Recalculate Style事件下一同捕獲CSS解析、CSSOM構(gòu)建以及computed styles的遞歸計(jì)算。
構(gòu)建渲染樹、布局及繪制
前面介紹了我們根據(jù)輸入的HTML及CSS構(gòu)建了DOM樹和CSSOM樹,但二者是獨(dú)立的對(duì)象:DOM描述的是文檔內(nèi)容,CSSOM描述的是應(yīng)用于文檔的樣式規(guī)則。瀏覽器會(huì)把DOM和CSSOM組合起來(lái)構(gòu)建一個(gè)渲染樹(Render-tree),渲染樹會(huì)捕獲頁(yè)面上所有可見(jiàn)的DOM內(nèi)容以及應(yīng)用在每個(gè)節(jié)點(diǎn)上的CSSOM樣式。
構(gòu)建渲染樹的過(guò)程大致如下:
1.從DOM樹的根節(jié)點(diǎn)開始,遍歷每個(gè)可見(jiàn)的節(jié)點(diǎn)
- 某些節(jié)點(diǎn)不可見(jiàn)(例如 script 標(biāo)簽、meta 標(biāo)簽等),因?yàn)樗鼈儾粫?huì)體現(xiàn)在渲染結(jié)果中,所以會(huì)被忽略
- 某些通過(guò) CSS 隱藏的節(jié)點(diǎn)在渲染樹中也會(huì)被忽略,比如應(yīng)用了 display:none 規(guī)則的節(jié)點(diǎn)
2.為每一個(gè)可見(jiàn)的節(jié)點(diǎn)匹配并應(yīng)用對(duì)應(yīng)的CSSOM規(guī)則
3.生成有內(nèi)容和計(jì)算樣式的可見(jiàn)節(jié)點(diǎn)
注意:小提示:注意visibility: hidden和display: none二者的區(qū)別。visibility: hidden只是讓元素在視覺(jué)上不可見(jiàn),但是元素在頁(yè)面布局中仍然占據(jù)空間。而display: none則是從渲染樹中刪除某一個(gè)元素,不僅視覺(jué)上不可見(jiàn),渲染樹上也沒(méi)有,更不會(huì)影響到頁(yè)面的布局。
最終輸出的就是一個(gè)包含了所有可見(jiàn)節(jié)點(diǎn)的內(nèi)容及樣式信息的渲染樹。
到目前為止,我們已經(jīng)計(jì)算出了哪些節(jié)點(diǎn)是可見(jiàn)的以及它們的計(jì)算樣式,但是我們還沒(méi)有計(jì)算它們?cè)谠O(shè)備視口(viewport)中的準(zhǔn)確位置及尺寸大小——這就是布局(Layout)階段要做的工作,也就是常說(shuō)的重排(reflow)。
為了計(jì)算出頁(yè)面中每個(gè)對(duì)象的準(zhǔn)確大小和位置,瀏覽器從渲染樹的根節(jié)點(diǎn)開始遍歷,計(jì)算頁(yè)面上每個(gè)對(duì)象的幾何信息。舉例如下:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>Critial Path: Hello world!</title></head><body><div style="width: 50%"><div style="width: 50%">Hello world!</div></div></body> </html>上面頁(yè)面的 body 包含兩個(gè)嵌套 div:第一個(gè) div(父元素)將節(jié)點(diǎn)尺寸大小設(shè)置為視口寬度的 50%,第二個(gè) div 的寬度為父元素的 50%,即視口寬度的 25%!
布局過(guò)程的輸出是一個(gè)“盒子模型”,它精確地捕獲了每個(gè)元素在視口中的準(zhǔn)確位置及尺寸大小:所有相對(duì)度量單位都被轉(zhuǎn)換為屏幕上的絕對(duì)像素。
自此,我們已經(jīng)知道了哪些節(jié)點(diǎn)是可見(jiàn)的以及它們的計(jì)算樣式和幾何信息,然后我們就可以把這些信息傳送到最后一個(gè)階段,即把渲染樹中的每一個(gè)節(jié)點(diǎn)都轉(zhuǎn)化到屏幕上實(shí)際的像素點(diǎn)。這個(gè)步驟通常被稱為繪制(painting)或者柵格化(rasterizing)。
構(gòu)建渲染樹、布局與繪制所消耗的時(shí)間也可以通過(guò)timeline來(lái)查看:
- “Layout” 事件捕獲渲染樹的構(gòu)建及位置、尺寸的計(jì)算
- 布局完成時(shí),瀏覽器會(huì)觸發(fā) ‘Paint’ 事件:將渲染樹轉(zhuǎn)化為屏幕上的實(shí)際像素
終于,我們的頁(yè)面在設(shè)備視口中可見(jiàn)了。
現(xiàn)在回顧一下瀏覽器執(zhí)行的幾個(gè)步驟:
- 處理 HTML 標(biāo)記,構(gòu)建 DOM 樹
- 處理 CSS 標(biāo)記,構(gòu)建 CSSOM 樹
- 將 DOM 樹和 CSSOM 樹融合成渲染樹
- 根據(jù)渲染樹進(jìn)行布局,計(jì)算每個(gè)節(jié)點(diǎn)的幾何信息
- 在屏幕上繪制各個(gè)節(jié)點(diǎn)
優(yōu)化CRP
阻塞渲染的CSS
在構(gòu)建渲染樹部分我們已了解到:CRP要求DOM和CSSOM兩者融合在一起才能構(gòu)建渲染樹。這就導(dǎo)致了一個(gè)性能問(wèn)題:HTML和CSS都是阻塞渲染的資源。HTML很顯然,沒(méi)有DOM就沒(méi)有內(nèi)容去渲染。CSS沒(méi)有那么明顯,但確實(shí)是阻塞渲染的資源。我們知道一個(gè)正常的網(wǎng)頁(yè)如果沒(méi)有引入專用的css,頁(yè)面有多丑陋。當(dāng)我們的網(wǎng)頁(yè)引入了專用的css,頁(yè)面一加載出來(lái)的時(shí)候就是絢麗多彩的,如果css不阻塞渲染,我們看到的很可能是這樣的一個(gè)畫面:頁(yè)面剛加載出來(lái)的時(shí)候其丑無(wú)比,過(guò)了一會(huì),頁(yè)面又變漂亮了……
既然CSS是阻塞渲染的資源,這就意味著在CSSOM構(gòu)建完成之前,瀏覽器不會(huì)去渲染任何已處理的內(nèi)容。要盡早、盡快地把CSS下載到客戶端以優(yōu)化首次渲染的時(shí)間。
使用CSS“媒體類型”和“媒體查詢”優(yōu)化阻塞渲染的CSS:
<link href="style.css" rel="stylesheet"> <link href="print.css" rel="stylesheet" media="print"> <link href="other.css" rel="stylesheet" media="(min-width: 40em)">- 第一條聲明阻塞渲染,匹配所有情況
- 第二條聲明只適用于打印(媒體類型),因此,頁(yè)面在瀏覽器中首次加載時(shí),不會(huì)阻塞渲染
- 第三條聲明提供了媒體查詢,由瀏覽器判斷:如果條件符合,則在該樣式表下載并處理完以前,瀏覽器會(huì)阻塞渲染
小提示:「阻塞渲染」僅是指該資源是否會(huì)阻塞瀏覽器的首次頁(yè)面渲染。無(wú)論 CSS 是否阻塞渲染,CSS 資源都會(huì)被下載,只是說(shuō)非阻塞性資源的優(yōu)先級(jí)比較低而已。
阻塞解析的JavaScript
js可以修改頁(yè)面的內(nèi)容、樣式以及響應(yīng)用戶的交互,JS在DOM、CSSOM和JS執(zhí)行之間引入了很多新的依賴關(guān)系,導(dǎo)致瀏覽器在處理和渲染頁(yè)面上出現(xiàn)大幅延遲:
- 當(dāng)瀏覽器遇到<script>標(biāo)簽時(shí),DOM構(gòu)建會(huì)暫停,直到腳本執(zhí)行完畢
- JavaScript 執(zhí)行會(huì)暫停,直到CSSOM準(zhǔn)備就緒
解析器阻塞 vs. 異步 JavaScript
默認(rèn)情況下,JavaScript 執(zhí)行會(huì)阻塞解析器:當(dāng)瀏覽器在文檔中遇到<script>標(biāo)簽時(shí),DOM構(gòu)建必須暫停,瀏覽器把控制權(quán)移交給JS引擎,JS引擎編譯并執(zhí)行腳本,腳本執(zhí)行完畢后再繼續(xù)構(gòu)建DOM。
事實(shí)上,內(nèi)聯(lián)腳本始終會(huì)阻塞解析器,除非你編寫額外的代碼來(lái)延遲它們的執(zhí)行。那通過(guò)<script>引入的外聯(lián)腳本呢?結(jié)果是一樣的,瀏覽器都會(huì)暫停,然后執(zhí)行腳本,腳本執(zhí)行完畢之后再去處理文檔的剩余部分。盡管如此,通過(guò)<script>引入外聯(lián)腳本還是有一個(gè)很大的好處。
默認(rèn)情況下,所有 JS 均會(huì)阻塞解析器,因?yàn)闉g覽器不知道腳本想在頁(yè)面上做什么,因此它必須假定最糟的情況并阻塞解析器。但是,如果我們能夠有個(gè)信號(hào)告知瀏覽器,說(shuō)腳本無(wú)需在文檔中引用它的確切位置被執(zhí)行呢?這樣一來(lái),瀏覽器就會(huì)繼續(xù)構(gòu)建DOM,并在腳本準(zhǔn)備就緒后執(zhí)行腳本。
這個(gè)信號(hào)就是async——在script標(biāo)簽里面添加async關(guān)鍵字,其有兩個(gè)特性:
- 告訴瀏覽器當(dāng)它碰到<script>標(biāo)簽時(shí)不用阻塞DOM構(gòu)建,因此瀏覽器會(huì)忽略腳本請(qǐng)求,繼續(xù)解析DOM
- JS執(zhí)行不依賴CSSOM:如果在CSSOM就緒之前腳本已經(jīng)就緒,腳本可以立即執(zhí)行
很顯然,這將會(huì)顯著提升性能!
分析CRP性能
先定義三個(gè)用于描述CRP的詞匯:
- 關(guān)鍵資源:能夠阻止網(wǎng)頁(yè)首次渲染的資源
- 關(guān)鍵路徑長(zhǎng)度:往返過(guò)程的數(shù)量,或者獲取所有關(guān)鍵資源所需的總時(shí)間
- 關(guān)鍵字節(jié):網(wǎng)頁(yè)首次渲染所需的總字節(jié)數(shù),是所有關(guān)鍵資源的傳輸文件大小總和
demo1:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><title>Critical Path: No Style</title></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div></body> </html>最簡(jiǎn)單的可用網(wǎng)頁(yè)僅由 HTML 標(biāo)記組成:無(wú) CSS、javascript 或其他類型的資源。要呈現(xiàn)此網(wǎng)頁(yè),瀏覽器必須初始化請(qǐng)求、等待 HTML 文檔準(zhǔn)備就緒、對(duì)其進(jìn)行解析、構(gòu)建 DOM,最后使其呈現(xiàn)在屏幕上。
- 1個(gè)關(guān)鍵資源
- 1個(gè)關(guān)鍵路徑長(zhǎng)度(假設(shè)文件很小)
- 5KB關(guān)鍵字節(jié)
T0 和 T1 之間的時(shí)間用于捕獲網(wǎng)絡(luò)傳輸和服務(wù)器處理時(shí)間。 在最理想的情況(HTML 文件較小)下,我們僅需一個(gè)網(wǎng)絡(luò)往返過(guò)程即可提取整個(gè)文檔(由于 TCP 傳輸協(xié)議的工作方式,較大的文件可能需要多個(gè)往返過(guò)程)。
demo2:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><link href="style.css" rel="stylesheet"></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div></body> </html>- 2個(gè)關(guān)鍵資源
- 2個(gè)或更多個(gè)關(guān)鍵路徑長(zhǎng)度
9KB關(guān)鍵字節(jié)
我們必須同時(shí)使用 HTML 和 CSS 來(lái)構(gòu)建渲染樹,因此 HTML 和 CSS 均為關(guān)鍵資源;瀏覽器需要一個(gè)網(wǎng)絡(luò)往返過(guò)程來(lái)提取 HTML 文檔,然后檢索到的標(biāo)記告知我們還需要 CSS 文件,這意味著,瀏覽器必須返回服務(wù)器并獲取 CSS,然后才能在屏幕上呈現(xiàn)網(wǎng)頁(yè),因此,該網(wǎng)頁(yè)最少需要兩個(gè)往返過(guò)程才能顯示(CSS 文件可能需要多個(gè)往返過(guò)程,重點(diǎn)在’最少’);兩種資源加起來(lái)的關(guān)鍵字節(jié)總量最多為 9 KB。
demo3:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><link href="style.css" rel="stylesheet"></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div><script src="app.js"></script></body> </html>- 3個(gè)關(guān)鍵資源
- 2個(gè)或更多個(gè)關(guān)鍵路徑長(zhǎng)度
11KB關(guān)鍵字節(jié)
我們有三個(gè)關(guān)鍵資源,關(guān)鍵字節(jié)總量最多為 11 KB,但是關(guān)鍵路徑長(zhǎng)度仍然是兩個(gè)往返過(guò)程,因?yàn)槲覀兛梢圆⑿袀鬏?CSS 和 JavaScript!
demo4: 如果app.js中的內(nèi)容不涉及到操作DOM和CSSOM,只是一些分析類型的代碼和其他不需要阻塞頁(yè)面渲染的代碼,則可以在<script>中加入“async”屬性:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><link href="style.css" rel="stylesheet"></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div><script src="app.js" async></script></body> </html>異步執(zhí)行腳本有以下幾項(xiàng)優(yōu)勢(shì):
- 腳本再也不會(huì)阻止解析器,所以也不再是CRP的組成部分
- 因?yàn)闆](méi)有其他關(guān)鍵腳本,CSS 也不需要阻止DomContentLoaded事件
- DomContentLoaded事件觸發(fā)得越早,其他應(yīng)用邏輯執(zhí)行的時(shí)間就越早
因此,經(jīng)過(guò)優(yōu)化的網(wǎng)頁(yè)恢復(fù)到了具有兩個(gè)關(guān)鍵資源(HTML 和 CSS)、具有兩個(gè)往返過(guò)程的最短關(guān)鍵路徑長(zhǎng)度和 9 KB 的關(guān)鍵字節(jié)總量。
demo5:
如果CSS樣式表僅適用于打印:
<html><head><meta name="viewport" content="width=device-width,initial-scale=1"><link href="style.css" rel="stylesheet" media="print"></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg"></div><script src="app.js" async></script></body> </html>因?yàn)?style.css 資源僅用于打印,所以只要DOM構(gòu)建完成,瀏覽器就具有了渲染網(wǎng)頁(yè)的足夠信息! 所以,該網(wǎng)頁(yè)僅具有一個(gè)關(guān)鍵資源(HTML),最小關(guān)鍵呈現(xiàn)路徑長(zhǎng)度為一個(gè)往返過(guò)程和5KB的關(guān)鍵字節(jié)。
優(yōu)化CRP
常規(guī)步驟:
文章轉(zhuǎn)載自https://segmentfault.com/a/1190000008550336
總結(jié)
以上是生活随笔為你收集整理的网站性能优化--CRP的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: swustoj水王C语言,swust西南
- 下一篇: 使用Nodejs发送邮件