新聞中心
本文會(huì)對(duì)web頁(yè)面的全鏈路進(jìn)行完整的講解并針對(duì)每一步找到能做的性能優(yōu)化點(diǎn),本文的目標(biāo)是極致的性能優(yōu)化。

成都創(chuàng)新互聯(lián)公司咨詢熱線:18980820575,為您提供成都網(wǎng)站建設(shè)網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),成都創(chuàng)新互聯(lián)公司網(wǎng)頁(yè)制作領(lǐng)域十載,包括成都混凝土攪拌機(jī)等多個(gè)領(lǐng)域擁有多年建站經(jīng)驗(yàn),選擇成都創(chuàng)新互聯(lián)公司,為網(wǎng)站錦上添花。
因?yàn)獒槍?duì)性能優(yōu)化,能做的點(diǎn)會(huì)特別特別的多,覆蓋著整個(gè)互聯(lián)網(wǎng)的訪問(wèn)流程,因此此文章的內(nèi)容會(huì)比較多且雜,筆者會(huì)盡量對(duì)內(nèi)容進(jìn)行分類講解。
本文的大致流程為先講理論知識(shí),比如如何評(píng)價(jià)一個(gè)頁(yè)面的性能好與不好、如果獲取性能指標(biāo),如何使用各種性能相關(guān)工具,瀏覽器如何獲取并渲染頁(yè)面。筆者認(rèn)為這些都是基礎(chǔ),只有了解了這些基礎(chǔ)才能開(kāi)始考慮如何去優(yōu)化。
接下來(lái)我們會(huì)進(jìn)入性能優(yōu)化環(huán)節(jié),在這個(gè)環(huán)節(jié)我會(huì)詳細(xì)講解在頁(yè)面的整個(gè)流程中,哪些地方可以做哪些優(yōu)化。
目錄
1.用戶輸入
2.卸載原頁(yè)面并重定向到新頁(yè)面
3.處理Service Worker
4.網(wǎng)絡(luò)請(qǐng)求
5.服務(wù)端響應(yīng)
6.瀏覽器渲染詳細(xì)流程
- 進(jìn)程與線程
- 輸入url到頁(yè)面展示完整過(guò)程
- 瀏覽器處理每一幀的流程
- Chrome Performance(性能)
- Chrome Performance 工具的使用
- Performance API介紹
- 使用Performance API獲取性能相關(guān)指標(biāo)
- Coverage(覆蓋率)
- Lighthouse
- Network(網(wǎng)絡(luò))
- 網(wǎng)絡(luò)請(qǐng)求中的Timing(時(shí)間)
- 網(wǎng)絡(luò)請(qǐng)求的優(yōu)先級(jí)
- 網(wǎng)頁(yè)總資源信息
- Network配置
- 網(wǎng)絡(luò)優(yōu)化策略
- 減少HTTP請(qǐng)求數(shù)
- 使用HTTP緩存
- 使用 HTTP/2.0
- 避免重定向
- 使用 dns-prefetch
- 使用域名分片
- CDN
- 壓縮
- 使用contenthash
- 合理使用preload、prefetch
- 瀏覽器渲染優(yōu)化策略
- 關(guān)鍵渲染路徑
- 強(qiáng)制同步布局問(wèn)題
- 如何減少重排與重繪
- 靜態(tài)文件優(yōu)化策略
- 圖片格式
- 圖片優(yōu)化
- HTML優(yōu)化
- CSS優(yōu)化
- JS優(yōu)化
- 字體優(yōu)化
- 瀏覽器儲(chǔ)存優(yōu)化策略
- Cookie
- LocalStorage
- SessionStorage
- IndexDB
- 其他優(yōu)化策略
- 使用PWA提高用戶體驗(yàn)
瀏覽器渲染原理
我們需要知道瀏覽器是如何渲染一個(gè)頁(yè)面的,我們才能知道如何對(duì)頁(yè)面進(jìn)行性能優(yōu)化,所以這里我們對(duì)一些基礎(chǔ)知識(shí)進(jìn)行講解
進(jìn)程與線程
瀏覽器有多種進(jìn)程,其中最主要的5種進(jìn)程如下
- 瀏覽器進(jìn)程 負(fù)責(zé)界面展示、用戶交互、子進(jìn)程管理、提供存儲(chǔ)等
- 渲染進(jìn)程 每個(gè)頁(yè)面都有一個(gè)單獨(dú)的渲染進(jìn)程,用于渲染頁(yè)面,包含webworker線程
- 網(wǎng)絡(luò)進(jìn)程 主要處理網(wǎng)絡(luò)資源加載(HTML、CSS、JS、IMAGE、AJAX等)
- GPU進(jìn)程 3D繪制,提高性能
- 插件進(jìn)程 chrome插件,每個(gè)插件占用一個(gè)進(jìn)程
輸入url到頁(yè)面展示完整過(guò)程
圖1
1.用戶輸入
用戶在 瀏覽器進(jìn)程 輸入并按下回車健后,瀏覽器判斷用戶輸入的url是否為正確的url,如果不是,則使用默認(rèn)的搜索引擎將該關(guān)鍵字拼接成url。
2.卸載原頁(yè)面并重定向到新頁(yè)面
然后瀏覽器會(huì)將現(xiàn)有頁(yè)面卸載掉并重定向到用戶新輸入的url頁(yè)面,也就是圖中【Process Unload Event】和【Redirect】流程。
此時(shí)瀏覽器會(huì)準(zhǔn)備一個(gè) 渲染進(jìn)程 用于渲染即將到來(lái)的頁(yè)面,和一個(gè) 網(wǎng)絡(luò)進(jìn)程 用于發(fā)送網(wǎng)絡(luò)請(qǐng)求。
3.處理Service Worker
如果當(dāng)前頁(yè)面注冊(cè)了Service Worker那么它可以攔截當(dāng)前網(wǎng)站所有的請(qǐng)求,進(jìn)行判斷是否需要向遠(yuǎn)程發(fā)送網(wǎng)絡(luò)請(qǐng)求。也就是圖中【Service Worker Init】與【Service Worker Fecth Event 】步驟
如果不需要發(fā)送網(wǎng)絡(luò)請(qǐng)求,則取本地文件。如果需要?jiǎng)t進(jìn)行下一步。
4.網(wǎng)絡(luò)請(qǐng)求
OSI網(wǎng)絡(luò)七層模型:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層、應(yīng)用層
在實(shí)際應(yīng)用中物理層、數(shù)據(jù)鏈路層被統(tǒng)稱為物理層,會(huì)話層、表示層、應(yīng)用層被統(tǒng)稱為應(yīng)用層,所以實(shí)際使用時(shí)通常分為4個(gè)層級(jí)
【物理層】>【網(wǎng)絡(luò)層(IP)】>【傳輸層(TCP/UDP)】>【應(yīng)用層(HTTP)】
也就是圖中【HTTP Cache】、【DNS】、【TCP】、【Request】、【Response】步驟
圖2
瀏覽器會(huì)拿著url通過(guò) 網(wǎng)絡(luò)進(jìn)程 進(jìn)行如下步驟
- HTTP/0.9 沒(méi)有請(qǐng)求頭和響應(yīng)頭,不區(qū)分傳輸?shù)膬?nèi)容類型,因?yàn)楫?dāng)時(shí)只傳輸HTML。
- HTTP/1.0 提供了請(qǐng)求頭和響應(yīng)頭,可以傳輸不同類型的內(nèi)容數(shù)據(jù)。根據(jù)請(qǐng)求響應(yīng)頭的不同來(lái)處理不同的資源,HTTP1.0每次發(fā)完請(qǐng)求都會(huì)斷開(kāi)TCP連接。有新的請(qǐng)求時(shí)再次創(chuàng)建TCP連接。
- HTTP/1.1 默認(rèn)開(kāi)啟了 keep-alive ,它能夠讓一個(gè)TCP連接中傳輸多個(gè)HTTP請(qǐng)求,也叫 鏈路復(fù)用 。但一個(gè)TCP連接同一時(shí)間只能發(fā)送一個(gè)HTTP請(qǐng)求,為了不阻塞多個(gè)請(qǐng)求,Chrome允許創(chuàng)建6個(gè)TCP連接,所以在HTTP/1.1中,最多能夠同時(shí)發(fā)送6個(gè)網(wǎng)絡(luò)請(qǐng)求
HTTP/2.0
多路復(fù)用
:
hpack
HTTP/3.0 使用UDP實(shí)現(xiàn),在UDP上一層加入一層 QUIC 協(xié)議,解決了TCP協(xié)議中的隊(duì)頭阻塞問(wèn)題。
- 根據(jù)url查詢本地是否已經(jīng)有強(qiáng)制緩存,如果有則判斷緩存是否過(guò)期,如果沒(méi)過(guò)期則直接返回緩存內(nèi)容,也就是圖1中【HTTP Cache】步驟
- 如果沒(méi)有強(qiáng)制緩存或者緩存已過(guò)期,則將該請(qǐng)求加入隊(duì)列進(jìn)行排隊(duì)準(zhǔn)備發(fā)送網(wǎng)絡(luò)請(qǐng)求,也就是圖2中【正在排隊(duì)】,然后進(jìn)入DNS解析階段,也就是圖1中【DNS】以及圖2中的【DNS查找】,DNS根據(jù)域名解析出對(duì)應(yīng)的IP地址。(DNS基于UDP)。
- 然后使用IP尋址找到對(duì)方,然后根據(jù)IP地址+端口號(hào)創(chuàng)建一個(gè)TCP連接(三次握手),也就是圖1中【TCP】以及圖2中的【初始連接】創(chuàng)建完成后利用TCP連接來(lái)傳輸數(shù)據(jù)。(TCP會(huì)將數(shù)據(jù)拆分為多個(gè)數(shù)據(jù)包,進(jìn)行有序傳輸,如果丟包會(huì)重發(fā),TCP的特點(diǎn)是可靠、有序)
- 判斷當(dāng)前協(xié)議是否為https,如果為https,則進(jìn)行SSL協(xié)商,將數(shù)據(jù)進(jìn)行加密,如果為http協(xié)議則不進(jìn)行加密(明文傳輸),也就是圖2中的【SSL】。
- 開(kāi)始發(fā)送http請(qǐng)求(請(qǐng)求行/請(qǐng)求頭/請(qǐng)求體),也就是圖1中【Request】以及圖2中的【已發(fā)送請(qǐng)求】。HTTP協(xié)議有多個(gè)版本,目前使用最多的版本為HTTP/1.1,HTTP/1.1發(fā)送完成后默認(rèn)不會(huì)斷開(kāi)。keep-alive 默認(rèn)打開(kāi),為了下次傳輸數(shù)據(jù)時(shí)復(fù)用上次創(chuàng)建的連接。每個(gè)域名最多同時(shí)建立6個(gè)TCP連接,所以同一時(shí)間最多發(fā)生6個(gè)請(qǐng)求。HTTP協(xié)議的各個(gè)版本特性如下:
- 服務(wù)器收到數(shù)據(jù)后解析HTTP請(qǐng)求(請(qǐng)求行/請(qǐng)求頭/請(qǐng)求體),處理完成后生成狀態(tài)碼和HTTP響應(yīng)(響應(yīng)行/響應(yīng)頭/響應(yīng)體)后返回給客戶端,也就是圖2的【等待中】在做的事情。
- 客戶端接收到HTTP響應(yīng)后根據(jù)狀態(tài)碼進(jìn)行對(duì)應(yīng)的處理,如果狀態(tài)碼為304則直接代表協(xié)商緩存生效,直接取本地的緩存文件。如果不是則下載內(nèi)容。也就是圖1中【Response】以及圖2中的【下載內(nèi)容】步驟。
5.服務(wù)端響應(yīng)
在 4.網(wǎng)絡(luò)請(qǐng)求 第 6 步中,服務(wù)器收到HTTP請(qǐng)求后需要根據(jù)請(qǐng)求信息來(lái)進(jìn)行解析,并返回給客戶端想要的數(shù)據(jù),這也就服務(wù)端響應(yīng)。
服務(wù)端可以響應(yīng)并返回給客戶端很多種類型的資源,這里主要介紹 html 類型
目前前端處理服務(wù)端響應(yīng)html請(qǐng)求主要分為SSR服務(wù)端渲染與CSR客戶端渲染,CSR就是返回一個(gè)空的HTML模版,然后瀏覽器加載js后通過(guò)js動(dòng)態(tài)渲染頁(yè)面。SSR是服務(wù)端在接受到請(qǐng)求時(shí)事先在服務(wù)端渲染好html返回給客戶端后,客戶端再進(jìn)行客戶端激活。
在打開(kāi)一個(gè)站點(diǎn)的首屏頁(yè)的完整鏈路中,使用SSR服務(wù)端渲染時(shí)的速度要遠(yuǎn)大于CSR客戶端渲染,并且SSR對(duì)SEO友好。所以對(duì)于首屏加載速度比較敏感或者需要優(yōu)化SEO的站點(diǎn)來(lái)說(shuō),使用SSR是更好的選擇。
6.瀏覽器渲染詳細(xì)流程
瀏覽器渲染詳細(xì)流程主要在 4.網(wǎng)絡(luò)請(qǐng)求 中的地 7 步。瀏覽器下載完 html 內(nèi)容后進(jìn)行解析何渲染頁(yè)面的流程。
渲染流程分為4種情況,
- HTML中無(wú)任何CSS相關(guān)標(biāo)簽
- CSS相關(guān)標(biāo)簽在HTML最頂部,且在解析到內(nèi)容標(biāo)簽( )時(shí)已經(jīng)解析完CSS相關(guān)標(biāo)簽
- CSS相關(guān)標(biāo)簽在HTML最頂部,但在解析到內(nèi)容標(biāo)簽( )時(shí)CSS相關(guān)標(biāo)簽尚未解析完
- CSS相關(guān)標(biāo)簽在HTML最底部
下面的流程是對(duì)上圖的文字版解析。讀者可將以上4種情況分別帶入到如下的渲染流程中走一遍。就能理解瀏覽器的完整渲染過(guò)程了。
【HTML】
瀏覽器收到html資源后先預(yù)掃描 和 并加載對(duì)應(yīng)資源
【HTML Parser】
對(duì)HTML字符串從上到下逐行解析,每解析完成一部分都會(huì)拿著解析結(jié)果進(jìn)入下一步驟
【DOM Tree】
css 相關(guān)標(biāo)簽跳過(guò)此步驟
如果當(dāng)前解析結(jié)果為
相關(guān)標(biāo)簽,則生成DOM樹(shù)( window.document )后進(jìn)入下一步。如果當(dāng)前解析結(jié)果為 相關(guān)標(biāo)簽且并且沒(méi)有添加異步屬性,則先停止【HTML Parser】的進(jìn)行,等待 資源加載完成后,然后按照以下2種情況處理,當(dāng)處理完成后便停止當(dāng)前 標(biāo)簽后續(xù)步驟的執(zhí)行,并繼續(xù)進(jìn)行新標(biāo)簽【HTML Parser】步驟的解析
- 如果HTML從未解析到過(guò)css相關(guān)節(jié)點(diǎn)則立即執(zhí)行。(此時(shí)頁(yè)面會(huì)把之前的內(nèi)容都顯示在頁(yè)面上)
- 如果HTML已經(jīng)解析到過(guò)css相關(guān)節(jié)點(diǎn)則等待css相關(guān)節(jié)點(diǎn)解析完成后再執(zhí)行。(在CSS解析完的一瞬間會(huì)觸發(fā)之前所有等待CSS資源解析的任務(wù),假如在解析之前還有的話,理論上應(yīng)該在執(zhí)行之前被繪制到頁(yè)面上,但因?yàn)镃hrome是按照貞為單位來(lái)進(jìn)行元素的繪制的,如果繪制與執(zhí)行的時(shí)間在一貞之內(nèi),則會(huì)因?yàn)樵诶L制時(shí)被js阻塞,所以實(shí)際上需要等js執(zhí)行完才會(huì)實(shí)際完成的繪制)
【Style Sheets】
相關(guān)標(biāo)簽跳過(guò)此步驟如果當(dāng)前解析結(jié)果為 css 相關(guān)標(biāo)簽,則等待其CSS資源加載完成,同時(shí)繼續(xù)進(jìn)行下一行的【HTML Parser】
【CSS Parser】
相關(guān)標(biāo)簽跳過(guò)此步驟當(dāng)CSS資源加載完畢后,對(duì)CSS從上到下逐行解析
【Style Rules】
相關(guān)標(biāo)簽跳過(guò)此步驟當(dāng)CSS解析完畢后,生成CSS規(guī)則樹(shù),也叫CSSOM,也就是 window.document.styleSheets
【Attachment】
根據(jù)DOM樹(shù)與CSS規(guī)則樹(shù)計(jì)算出每個(gè)節(jié)點(diǎn)的具體樣式。
分為兩種情況
1. 如果當(dāng)前節(jié)點(diǎn)為 相關(guān)節(jié)點(diǎn)
如果HTML從未解析到過(guò) css 相關(guān)標(biāo)簽則使用HTML默認(rèn)樣式,如果已經(jīng)解析到過(guò) css 相關(guān)標(biāo)簽則阻塞等待 css 標(biāo)簽也完成【Attachment】步驟后才進(jìn)入下一步。
2. 如果當(dāng)前節(jié)點(diǎn)為 css 相關(guān)節(jié)點(diǎn)
則需要根據(jù)是否在之前已經(jīng)渲染過(guò)CSS資源中對(duì)應(yīng)的DOM節(jié)點(diǎn),如果已經(jīng)渲染過(guò)則需要重繪。如果未渲染過(guò)任何相關(guān)DOM節(jié)點(diǎn)則此步驟為最后一步。
【Render Tree】
生成渲染樹(shù),在此階段已經(jīng)可以將具體的某個(gè)
與對(duì)應(yīng)的CSS樣式對(duì)應(yīng)起來(lái)了。有了渲染樹(shù)后瀏覽器就能根據(jù)當(dāng)前瀏覽器的狀態(tài)計(jì)算出某個(gè)DOM節(jié)點(diǎn)的樣式、大小、寬度、是否獨(dú)占一行等信息。計(jì)算完成后把一些不需要顯示出來(lái)的節(jié)點(diǎn)在渲染樹(shù)中刪掉。如 display: none 。【Layout】
通過(guò)渲染樹(shù)進(jìn)行分層(根據(jù)定位屬性、透明屬性、transform屬性、clip屬性等)生成圖層樹(shù)。
【Painting】
繪制所有圖層,并轉(zhuǎn)交給合成線程來(lái)最最終的合并所有圖層的處理。
【Display】
最終生成頁(yè)面并顯示到瀏覽器上
瀏覽器處理每一幀的流程
瀏覽器在渲染完頁(yè)面之后還需要不間斷的處理很多內(nèi)容的,比如動(dòng)畫、用戶事件、定時(shí)器等。因此當(dāng)瀏覽器渲染完頁(yè)面后,還會(huì)在之后的每一幀到來(lái)時(shí)執(zhí)行以下的流程。
- touch wheel click keypress
- 【JS】處理完用戶事件后執(zhí)行【定時(shí)器Timers】
- 【Begin frame】處理完定時(shí)器后開(kāi)始進(jìn)行【每幀事件Per frame events】的處理,包括窗口大小改變、滾動(dòng)、媒體查詢的更改、動(dòng)畫事件。
- 【rAF】處理完幀事件后執(zhí)行 requestAnimationFrame 回調(diào)函數(shù)和 IntersectionObserver 回調(diào)函數(shù)。
- 【Layout】然后【重新計(jì)算樣式Recalc style】、【更新布局Update layout】、【調(diào)整Observer回調(diào)的大小Resize Observer callbacks】
- 【Paint】然后【合成更新Compositing update】、【Paint invalidation】、【Record】
Chrome性能優(yōu)化相關(guān)工具
了解完瀏覽器渲染原理,我們還需要知道根據(jù)哪些指標(biāo)才能判斷一個(gè)頁(yè)面性能的好壞,在Chrome中這些指標(biāo)應(yīng)該怎么獲取。以及Chrome都為我們提供了哪些性能相關(guān)的工具,如何使用。
Chrome Performance(性能)
Performance既是一個(gè)Chrome工具,可用于性能檢測(cè)。
同樣又是一套JS API,可在Chrome中執(zhí)行。
Chrome Performance 工具的使用
打開(kāi)Chrome調(diào)試面板選擇 Performance ,中文版為 性能 ,點(diǎn)擊刷新按鈕,Performance會(huì)刷新并錄制當(dāng)前頁(yè)面,然后我們就可以在面板中看到如下的各種性能相關(guān)細(xì)節(jié)。
Performance API介紹
js中存在Performance API,可用于性能檢測(cè),具體如下
- 【Process Unload Event】等待上一個(gè)頁(yè)面卸載。在我們輸入url后瀏覽器需要卸載上一個(gè)頁(yè)面的內(nèi)容然后再去執(zhí)行 navigationStart 導(dǎo)航開(kāi)始。
- 【Redirect】瀏覽器卸載完上一個(gè)頁(yè)面后會(huì)執(zhí)行 redirectStart 然后將當(dāng)前頁(yè)面重定向到用戶新輸入的url頁(yè)面。完成重定向后會(huì)執(zhí)行 redirectEnd
- 【Service Worker Init】如果當(dāng)前頁(yè)面注冊(cè)了Service Worker那么執(zhí)行 workerStart 對(duì)Service Worker進(jìn)行初始化操作。
- 【Service Worker Fecth Event 】瀏覽器準(zhǔn)備好發(fā)送請(qǐng)求,在發(fā)送之前會(huì)執(zhí)行 fetchStart
- 【HTTP Cache】如果有緩存則直接取緩存,如果沒(méi)有的話則繼續(xù)解析
- 【DNS】如果沒(méi)有緩存則執(zhí)行 domainLookupStart 然后去解析DNS,解析完會(huì)執(zhí)行 domainLookupEnd
- contentStart secureConnectionStart contentEnd
- 【Request】TCP連接創(chuàng)建完成后執(zhí)行 requestStart ,然后開(kāi)始真正的發(fā)送請(qǐng)求
- 【Response】請(qǐng)求被響應(yīng)且首字節(jié)返回時(shí)會(huì)先執(zhí)行 responseStart ,響應(yīng)全部接收完畢后會(huì)執(zhí)行 responseEnd
- domLoading domInteractive domContentLoadedEventStart DOMContentLoaded domContentLoadedEventEnd DCL domComplete
- loadEventStart window.onload load loadEventEnd
使用Performance API獲取性能相關(guān)指標(biāo)
接下來(lái)我們來(lái)了解一下目前常用的性能指標(biāo),并且我們需要知道其中一些關(guān)鍵指標(biāo)如何用Performance API獲取。
TTFB 首字節(jié)時(shí)間
TTFB(Time To First Byte) : 從發(fā)送請(qǐng)求到數(shù)據(jù)返回第一個(gè)字節(jié)所消耗的時(shí)間
const { responseStart, requestStart } = performance.timing
const TTFB = responseStart - requestStart
FP 首次繪制
FP (First Paint) 首次繪制 : 第一個(gè)像素繪制到頁(yè)面上的時(shí)間
const paint = performance.getEntriesByType('paint')
const FP = paint[0].startTime
FCP 首次內(nèi)容繪制
FCP (First Contentful Paint) 首次內(nèi)容繪制 標(biāo)記瀏覽器渲染來(lái)自 DOM 第一位內(nèi)容的時(shí)間點(diǎn),該內(nèi)容可能是文本、圖像、SVG 甚至 元素.
const paint = performance.getEntriesByType('paint')
const FCP = paint[1].startTime
FMP 首次有效繪制
FMP(First Meaningful Paint) 首次有效繪制 : 例如,在 YouTube 觀看頁(yè)面上,主視頻就是主角元素.
圖片可以沒(méi)加載完成,但整體的骨架已經(jīng)加載完成了。
1秒內(nèi)完成FMP的概率超過(guò)80%,那就代表這個(gè)網(wǎng)站是一個(gè)性能較好的網(wǎng)站
let FMP = 0
const performanceObserverFMP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FMP = entries[0].startTime
})
// 需要在元素中添加 elementtiming="meaningful"
performanceObserverFMP.observe({ entryTypes: ['element'] })
TTI 可交互時(shí)間
TTI (Time to Interactive) 可交互時(shí)間 : DOM樹(shù)構(gòu)建完畢,可以綁定事件的時(shí)間
const { domInteractive, fetchStart } = performance.timing
const TTI = domInteractive - fetchStart
LCP 最大內(nèi)容渲染
LCP (Largest Contentful Paint) 最大內(nèi)容渲染 : 代表在viewport中最大的頁(yè)面元素加載的時(shí)間. LCP的數(shù)據(jù)會(huì)通過(guò)PerformanceEntry對(duì)象記錄, 每次出現(xiàn)更大的內(nèi)容渲染, 則會(huì)產(chǎn)生一個(gè)新的PerformanceEntry對(duì)象.(2019年11月新增)
let LCP = 0
const performanceObserverLCP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
LCP = entries[entries.length - 1].startTime
})
performanceObserverLCP.observe({ entryTypes: ['largest-contentful-paint'] })
DCL
DCL (DomContentloaded) : 當(dāng) HTML 文檔被完全加載和解析完成之后,DOMContentLoaded 事件被觸發(fā),無(wú)需等待樣式表、圖像和子框架的完成加載
const { domContentLoadedEventEnd, fetchStart } = performance.timing
const DCL = domContentLoadedEventEnd - fetchStart
L 全部加載完畢
L (onLoad) , 當(dāng)依賴的資源(圖片、文件等), 全部加載完畢之后才會(huì)觸發(fā)
const { loadEventStart, fetchStart } = performance.timing
const L = loadEventStart - fetchStart
FID 首次輸入延遲
FID (First Input Delay) 首次輸入延遲 : 指標(biāo)衡量的是從用戶首次與您的網(wǎng)站進(jìn)行交互(即當(dāng)他們單擊鏈接,點(diǎn)擊按鈕等)到瀏覽器實(shí)際能夠訪問(wèn)之間的時(shí)間
let FID = 0
const performanceObserverFID = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FID = entries[0].processingStart - entries[0].startTime
})
performanceObserverFID.observe({ type: ['first-input'], buffered: true })
TBT 頁(yè)面阻塞總時(shí)長(zhǎng)
TBT (Total Blocking Time) 頁(yè)面阻塞總時(shí)長(zhǎng) : TBT匯總所有加載過(guò)程中阻塞用戶操作的時(shí)長(zhǎng),在FCP和TTI之間任何long task中阻塞部分都會(huì)被匯總
CLS 累積布局偏移
CLS (Cumulative Layout Shift) 累積布局偏移 : 總結(jié)起來(lái)就是一個(gè)元素初始時(shí)和其hidden之間的任何時(shí)間如果元素偏移了, 則會(huì)被計(jì)算進(jìn)去, 具體的計(jì)算方法可看這篇文章 https://web.dev/cls/
SI
SI (Speed Index) : 指標(biāo)用于顯示頁(yè)面可見(jiàn)部分的顯示速度, 單位是時(shí)間
Coverage(覆蓋率)
獲取代碼未使用占比
Lighthouse
獲取性能報(bào)告并查看推薦優(yōu)化項(xiàng)
可以在本地安裝命令行工具來(lái)使用,也可以通過(guò)Chrome來(lái)使用。
命令行方式使用
npm install -g lighthouse
lighthouse --view https://m.baidu.com
在Chrome中使用
Network(網(wǎng)絡(luò))
網(wǎng)絡(luò)請(qǐng)求中的Timing(時(shí)間)
能獲取網(wǎng)絡(luò)請(qǐng)求的時(shí)間消耗細(xì)節(jié),可以根據(jù)耗時(shí)來(lái)決定優(yōu)化策略。優(yōu)先優(yōu)化耗時(shí)最長(zhǎng)的
【正在排隊(duì)】網(wǎng)絡(luò)請(qǐng)求隊(duì)列的排隊(duì)時(shí)間
【已停止】阻塞住用于處理其他事情的時(shí)間
【DNS查找】用于DNS解析IP地址的時(shí)間
【初始連接】創(chuàng)建TCP連接時(shí)間
【SSL】用于SSL協(xié)商的時(shí)間
【已發(fā)送請(qǐng)求】用于發(fā)送請(qǐng)求的時(shí)間
【等待中】請(qǐng)求發(fā)出至接收響應(yīng)的時(shí)間也可以理解為服務(wù)端處理請(qǐng)求的時(shí)間
【下載內(nèi)容】下載響應(yīng)的時(shí)間
網(wǎng)絡(luò)請(qǐng)求的優(yōu)先級(jí)
瀏覽器會(huì)根據(jù)資源的類型決定優(yōu)先請(qǐng)求哪些資源,優(yōu)先級(jí)高的請(qǐng)求能夠優(yōu)先被加載。
右擊此處勾選優(yōu)先級(jí)可打開(kāi)優(yōu)先級(jí)功能,在請(qǐng)求中便可看到網(wǎng)絡(luò)請(qǐng)求的優(yōu)先級(jí)
不同資源類型的優(yōu)先級(jí)排序如下
【最高】html、style
【高】font、fetch、script
【低】image、track
網(wǎng)頁(yè)總資源信息
【58個(gè)請(qǐng)求】網(wǎng)頁(yè)一共多少個(gè)請(qǐng)求
【6.9 MB 項(xiàng)資源】網(wǎng)頁(yè)資源一共6.9MB大小
【DOMContentLoaded:454 毫秒】DOM加載完畢的時(shí)長(zhǎng)
【加載時(shí)間:1.02 秒】onload完畢的時(shí)長(zhǎng)
Network配置
網(wǎng)頁(yè)性能優(yōu)化
上面我們分別講解了進(jìn)程與線程、瀏覽器打開(kāi)一個(gè)頁(yè)面的完整過(guò)程、瀏覽器處理每一幀時(shí)的流程、Chrome性能相關(guān)的各種工具以及性能相關(guān)的各種指標(biāo)。以上內(nèi)容都掌握之后我們?cè)倏紤]性能優(yōu)化遍有了思路,我們?cè)陧?yè)面展示的任意一個(gè)步驟中對(duì)其進(jìn)行優(yōu)化都能對(duì)整個(gè)網(wǎng)頁(yè)的展示性能產(chǎn)生影響。
下面列出了一個(gè)頁(yè)面能優(yōu)化的所有內(nèi)容,讀者可根據(jù)自己的業(yè)務(wù)情況結(jié)合性能工具來(lái)做適合自己的優(yōu)化方式。
網(wǎng)絡(luò)優(yōu)化策略
減少HTTP請(qǐng)求數(shù)
合并JS、合并CSS、合理內(nèi)嵌JS和CSS、使用雪碧圖
使用HTTP緩存
使用強(qiáng)制緩存可以不走網(wǎng)絡(luò)請(qǐng)求,直接走本地緩存數(shù)據(jù)來(lái)加載資源。
使用協(xié)商緩存可以減少數(shù)據(jù)傳輸,當(dāng)不需要更新數(shù)據(jù)時(shí)可通知客戶端直接使用本地緩存。
使用 HTTP/2.0
HTTP/2.0使用同一個(gè)TCP連接來(lái)發(fā)送數(shù)據(jù),他把多個(gè)請(qǐng)求通過(guò)二進(jìn)制分貞層實(shí)現(xiàn)了分貞,然后把數(shù)據(jù)傳輸給服務(wù)器。也叫 多路復(fù)用 ,多個(gè)請(qǐng)求復(fù)用同一個(gè)TCP連接。
HTTP/2.0會(huì)將所有以 : 開(kāi)頭的請(qǐng)求頭做一個(gè)映射表,然后使用 hpack 進(jìn)行壓縮,使用這種方式會(huì)使請(qǐng)求頭更小。
服務(wù)器可主動(dòng)推送數(shù)據(jù)給客戶端。
避免重定向
301、302 重定向會(huì)降低響應(yīng)速度
使用 dns-prefetch
DNS請(qǐng)求雖然占用的帶寬較少,但會(huì)有很高的延遲,由其在移動(dòng)端網(wǎng)絡(luò)會(huì)更加明顯。
使用dns-prefetch可以對(duì)網(wǎng)站中使用到的域名提前進(jìn)行解析。提高資源加載速度。
通過(guò)dns預(yù)解析技術(shù)可以很好的降低延遲,在訪問(wèn)以圖片為主的移動(dòng)端網(wǎng)站時(shí),使用DNS預(yù)解析的情意中下頁(yè)面加載時(shí)間可以減少5%。
使用域名分片
在HTTP/1.1中,一個(gè)域名同時(shí)最多創(chuàng)建6個(gè)TCP連接,將資源放在多個(gè)域名下可提高請(qǐng)求的并發(fā)數(shù)
CDN
靜態(tài)資源全上CDN,CDN能非常有效的加快網(wǎng)站靜態(tài)資源的訪問(wèn)速度。
壓縮
gzip壓縮、html壓縮、js壓縮、css壓縮、圖片壓縮
使用contenthash
contenthash可以根據(jù)文件內(nèi)容在文件名中加hash,可用于瀏覽器緩存文件,當(dāng)文件沒(méi)有改變時(shí)便直接取本地緩存數(shù)據(jù)
合理使用preload、prefetch
preload預(yù)加載、prefetch空閑時(shí)間加載
兩者都不會(huì)阻塞 onload 事件, prefetch 會(huì)在頁(yè)面空閑時(shí)候再進(jìn)行加載,是提前預(yù)加載之后可能要用到的資源,不一定是當(dāng)前頁(yè)面使用的, preload 預(yù)加載的是當(dāng)前頁(yè)面的資源。
Document
如上代碼,預(yù)加載了css但并沒(méi)有使用。瀏覽器在頁(yè)面 onload 完成一段時(shí)間后,發(fā)現(xiàn)還沒(méi)有引用預(yù)加載的資源時(shí),瀏覽器會(huì)在控制臺(tái)輸出下圖的提示信息
preload和prefetch可根據(jù)資源類型決定資源加載的優(yōu)先級(jí),詳細(xì)優(yōu)先級(jí)如代碼
Document
瀏覽器渲染優(yōu)化策略
關(guān)鍵渲染路徑
當(dāng)通過(guò)JS或者其他任意方式修改DOM后,瀏覽器會(huì)進(jìn)入如下流程
【JS通過(guò)API修改DOM】>【計(jì)算樣式】>【布局(重排)】>【繪制(重繪)】>【合成】
Reflow 重排 :重排在Chrome Performance中叫做布局,通常添加或刪除元素、修改元素大小、移動(dòng)元素位置、獲取位置信息都會(huì)觸發(fā)頁(yè)面的重排,因?yàn)橹嘏趴赡軙?huì)改變?cè)氐拇笮∥恢玫刃畔?,這樣的改變會(huì)影響到頁(yè)面大量其它元素的大小位置信息,會(huì)耗費(fèi)掉大量的性能,所以在實(shí)際應(yīng)用中我們應(yīng)該盡可能的減少重排
Repaint 重繪 :重繪在Chrome Performance中叫做繪制,通常樣式改變但沒(méi)有影響位置時(shí)會(huì)觸發(fā)重繪操作,重繪性能還好,但我們也需要盡量減少重繪,如果需要做一些動(dòng)畫,我們盡量使用CSS3動(dòng)畫,CSS3動(dòng)畫只需要在初始化時(shí)繪制一次,之后的動(dòng)畫都不會(huì)觸發(fā)重繪操作。
強(qiáng)制同步布局問(wèn)題
在同一個(gè)函數(shù)內(nèi),修改元素后又獲取元素的位置時(shí)會(huì)觸發(fā)強(qiáng)制同步布局,影響渲染性能
強(qiáng)制同步布局會(huì)使js強(qiáng)制將【計(jì)算樣式】和【布局(重排)】操作提前到當(dāng)前函數(shù)任務(wù)中,這樣會(huì)導(dǎo)致每次運(yùn)行時(shí)執(zhí)行一次【計(jì)算樣式】和【重排】,這樣一定會(huì)影響頁(yè)面渲染性能,而正常情況下【計(jì)算樣式】和【重排】操作會(huì)在函數(shù)結(jié)束后統(tǒng)一執(zhí)行。
Document
在函數(shù)運(yùn)行時(shí)執(zhí)行了10次【計(jì)算樣式】和【重排】
反復(fù)觸發(fā)強(qiáng)制同步布局也叫 布局抖動(dòng)
分享題目:Web頁(yè)面全鏈路性能優(yōu)化指南
鏈接地址:http://www.fisionsoft.com.cn/article/djcjhje.html


咨詢
建站咨詢
