Web頁面全鏈路性能優(yōu)化指南

性能優(yōu)化不單指優(yōu)化一個頁面的打開速度,在開發(fā)環(huán)境將一個項(xiàng)目的啟動時間縮短使開發(fā)體驗(yàn)更好也屬于性能優(yōu)化,大文件上傳時為其添加分片上傳、斷點(diǎn)續(xù)傳也屬于性能優(yōu)化。在項(xiàng)目開發(fā)以及用戶使用的過程中,能夠讓任何一個鏈路快一點(diǎn),都可以被叫做性能優(yōu)化。
本文會對web頁面的全鏈路進(jìn)行完整的講解并針對每一步找到能做的性能優(yōu)化點(diǎn),本文的目標(biāo)是極致的性能優(yōu)化。
因?yàn)獒槍π阅軆?yōu)化,能做的點(diǎn)會特別特別的多,覆蓋著整個互聯(lián)網(wǎng)的訪問流程,因此此文章的內(nèi)容會比較多且雜,筆者會盡量對內(nèi)容進(jìn)行分類講解。
本文的大致流程為先講理論知識,比如如何評價一個頁面的性能好與不好、如果獲取性能指標(biāo),如何使用各種性能相關(guān)工具,瀏覽器如何獲取并渲染頁面。筆者認(rèn)為這些都是基礎(chǔ),只有了解了這些基礎(chǔ)才能開始考慮如何去優(yōu)化。
接下來我們會進(jìn)入性能優(yōu)化環(huán)節(jié),在這個環(huán)節(jié)我會詳細(xì)講解在頁面的整個流程中,哪些地方可以做哪些優(yōu)化。
目錄
進(jìn)程與線程
輸入url到頁面展示完整過程
1.用戶輸入
2.卸載原頁面并重定向到新頁面
3.處理Service Worker
4.網(wǎng)絡(luò)請求
5.服務(wù)端響應(yīng)
6.瀏覽器渲染詳細(xì)流程
瀏覽器處理每一幀的流程
Chrome Performance(性能)
Chrome Performance 工具的使用
Performance API介紹
使用Performance API獲取性能相關(guān)指標(biāo)
Coverage(覆蓋率)
Lighthouse
Network(網(wǎng)絡(luò))
網(wǎng)絡(luò)請求中的Timing(時間)
網(wǎng)絡(luò)請求的優(yōu)先級
網(wǎng)頁總資源信息
Network配置
網(wǎng)絡(luò)優(yōu)化策略
減少HTTP請求數(shù)
使用HTTP緩存
使用 HTTP/2.0
避免重定向
使用 dns-prefetch
使用域名分片
CDN
壓縮
使用contenthash
合理使用preload、prefetch
瀏覽器渲染優(yōu)化策略
關(guān)鍵渲染路徑
強(qiáng)制同步布局問題
如何減少重排與重繪
靜態(tài)文件優(yōu)化策略
圖片格式
圖片優(yōu)化
HTML優(yōu)化
CSS優(yōu)化
JS優(yōu)化
字體優(yōu)化
瀏覽器儲存優(yōu)化策略
Cookie
LocalStorage
SessionStorage
IndexDB
其他優(yōu)化策略
使用PWA提高用戶體驗(yàn)
瀏覽器渲染原理
我們需要知道瀏覽器是如何渲染一個頁面的,我們才能知道如何對頁面進(jìn)行性能優(yōu)化,所以這里我們對一些基礎(chǔ)知識進(jìn)行講解
進(jìn)程與線程
瀏覽器有多種進(jìn)程,其中最主要的5種進(jìn)程如下

瀏覽器進(jìn)程 負(fù)責(zé)界面展示、用戶交互、子進(jìn)程管理、提供存儲等 渲染進(jìn)程 每個頁面都有一個單獨(dú)的渲染進(jìn)程,用于渲染頁面,包含webworker線程 網(wǎng)絡(luò)進(jìn)程 主要處理網(wǎng)絡(luò)資源加載(HTML、CSS、JS、IMAGE、AJAX等) GPU進(jìn)程 3D繪制,提高性能 插件進(jìn)程 chrome插件,每個插件占用一個進(jìn)程
輸入url到頁面展示完整過程
圖1

1.用戶輸入
用戶在瀏覽器進(jìn)程輸入并按下回車健后,瀏覽器判斷用戶輸入的url是否為正確的url,如果不是,則使用默認(rèn)的搜索引擎將該關(guān)鍵字拼接成url。
2.卸載原頁面并重定向到新頁面
然后瀏覽器會將現(xiàn)有頁面卸載掉并重定向到用戶新輸入的url頁面,也就是圖中【Process Unload Event】和【Redirect】流程。
此時瀏覽器會準(zhǔn)備一個渲染進(jìn)程用于渲染即將到來的頁面,和一個網(wǎng)絡(luò)進(jìn)程用于發(fā)送網(wǎng)絡(luò)請求。
3.處理Service Worker
如果當(dāng)前頁面注冊了Service Worker那么它可以攔截當(dāng)前網(wǎng)站所有的請求,進(jìn)行判斷是否需要向遠(yuǎn)程發(fā)送網(wǎng)絡(luò)請求。也就是圖中【Service Worker Init】與【Service Worker Fecth Event 】步驟
如果不需要發(fā)送網(wǎng)絡(luò)請求,則取本地文件。如果需要則進(jìn)行下一步。
4.網(wǎng)絡(luò)請求
OSI網(wǎng)絡(luò)七層模型:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會話層、表示層、應(yīng)用層
在實(shí)際應(yīng)用中物理層、數(shù)據(jù)鏈路層被統(tǒng)稱為物理層,會話層、表示層、應(yīng)用層被統(tǒng)稱為應(yīng)用層,所以實(shí)際使用時通常分為4個層級
【物理層】>【網(wǎng)絡(luò)層(IP)】>【傳輸層(TCP/UDP)】>【應(yīng)用層(HTTP)】
也就是圖中【HTTP Cache】、【DNS】、【TCP】、【Request】、【Response】步驟
圖2

瀏覽器會拿著url通過網(wǎng)絡(luò)進(jìn)程進(jìn)行如下步驟
根據(jù)url查詢本地是否已經(jīng)有強(qiáng)制緩存,如果有則判斷緩存是否過期,如果沒過期則直接返回緩存內(nèi)容,也就是圖1中【HTTP Cache】步驟
如果沒有強(qiáng)制緩存或者緩存已過期,則將該請求加入隊(duì)列進(jìn)行排隊(duì)準(zhǔn)備發(fā)送網(wǎng)絡(luò)請求,也就是圖2中【正在排隊(duì)】,然后進(jìn)入DNS解析階段,也就是圖1中【DNS】以及圖2中的【DNS查找】,DNS根據(jù)域名解析出對應(yīng)的IP地址。(DNS基于UDP)。
然后使用IP尋址找到對方,然后根據(jù)IP地址+端口號創(chuàng)建一個TCP連接(三次握手),也就是圖1中【TCP】以及圖2中的【初始連接】創(chuàng)建完成后利用TCP連接來傳輸數(shù)據(jù)。(TCP會將數(shù)據(jù)拆分為多個數(shù)據(jù)包,進(jìn)行有序傳輸,如果丟包會重發(fā),TCP的特點(diǎn)是可靠、有序)
判斷當(dāng)前協(xié)議是否為https,如果為https,則進(jìn)行SSL協(xié)商,將數(shù)據(jù)進(jìn)行加密,如果為http協(xié)議則不進(jìn)行加密(明文傳輸),也就是圖2中的【SSL】。
開始發(fā)送http請求(請求行/請求頭/請求體),也就是圖1中【Request】以及圖2中的【已發(fā)送請求】。HTTP協(xié)議有多個版本,目前使用最多的版本為HTTP/1.1,HTTP/1.1發(fā)送完成后默認(rèn)不會斷開。keep-alive 默認(rèn)打開,為了下次傳輸數(shù)據(jù)時復(fù)用上次創(chuàng)建的連接。每個域名最多同時建立6個TCP連接,所以同一時間最多發(fā)生6個請求。
HTTP協(xié)議的各個版本特性如下:
HTTP/0.9沒有請求頭和響應(yīng)頭,不區(qū)分傳輸?shù)膬?nèi)容類型,因?yàn)楫?dāng)時只傳輸HTML。HTTP/1.0提供了請求頭和響應(yīng)頭,可以傳輸不同類型的內(nèi)容數(shù)據(jù)。根據(jù)請求響應(yīng)頭的不同來處理不同的資源,HTTP1.0每次發(fā)完請求都會斷開TCP連接。有新的請求時再次創(chuàng)建TCP連接。HTTP/1.1默認(rèn)開啟了 keep-alive ,它能夠讓一個TCP連接中傳輸多個HTTP請求,也叫鏈路復(fù)用。但一個TCP連接同一時間只能發(fā)送一個HTTP請求,為了不阻塞多個請求,Chrome允許創(chuàng)建6個TCP連接,所以在HTTP/1.1中,最多能夠同時發(fā)送6個網(wǎng)絡(luò)請求。HTTP/2.0HTTP/2.0使用同一個TCP連接來發(fā)送數(shù)據(jù),他把多個請求通過二進(jìn)制分貞層實(shí)現(xiàn)了分貞,然后把數(shù)據(jù)傳輸給服務(wù)器。也叫多路復(fù)用,多個請求復(fù)用同一個TCP連接。HTTP/2.0會將所有以:開頭的請求頭做一個映射表,然后使用hpack進(jìn)行壓縮,使用這種方式會使請求頭更小。服務(wù)器可主動推送數(shù)據(jù)給客戶端。HTTP/3.0使用UDP實(shí)現(xiàn),在UDP上一層加入一層QUIC協(xié)議,解決了TCP協(xié)議中的隊(duì)頭阻塞問題。服務(wù)器收到數(shù)據(jù)后解析HTTP請求(請求行/請求頭/請求體),處理完成后生成狀態(tài)碼和HTTP響應(yīng)(響應(yīng)行/響應(yīng)頭/響應(yīng)體)后返回給客戶端,也就是圖2的【等待中】在做的事情。
客戶端接收到HTTP響應(yīng)后根據(jù)狀態(tài)碼進(jìn)行對應(yīng)的處理,如果狀態(tài)碼為304則直接代表協(xié)商緩存生效,直接取本地的緩存文件。如果不是則下載內(nèi)容。也就是圖1中【Response】以及圖2中的【下載內(nèi)容】步驟。
5.服務(wù)端響應(yīng)
在4.網(wǎng)絡(luò)請求第6步中,服務(wù)器收到HTTP請求后需要根據(jù)請求信息來進(jìn)行解析,并返回給客戶端想要的數(shù)據(jù),這也就服務(wù)端響應(yīng)。
服務(wù)端可以響應(yīng)并返回給客戶端很多種類型的資源,這里主要介紹html類型
目前前端處理服務(wù)端響應(yīng)html請求主要分為SSR服務(wù)端渲染與CSR客戶端渲染,CSR就是返回一個空的HTML模版,然后瀏覽器加載js后通過js動態(tài)渲染頁面。SSR是服務(wù)端在接受到請求時事先在服務(wù)端渲染好html返回給客戶端后,客戶端再進(jìn)行客戶端激活。
在打開一個站點(diǎn)的首屏頁的完整鏈路中,使用SSR服務(wù)端渲染時的速度要遠(yuǎn)大于CSR客戶端渲染,并且SSR對SEO友好。所以對于首屏加載速度比較敏感或者需要優(yōu)化SEO的站點(diǎn)來說,使用SSR是更好的選擇。
6.瀏覽器渲染詳細(xì)流程
瀏覽器渲染詳細(xì)流程主要在4.網(wǎng)絡(luò)請求中的地7步。瀏覽器下載完html內(nèi)容后進(jìn)行解析何渲染頁面的流程。

渲染流程分為4種情況,
HTML中無任何CSS相關(guān)標(biāo)簽 CSS相關(guān)標(biāo)簽在HTML最頂部,且在解析到內(nèi)容標(biāo)簽( )時已經(jīng)解析完CSS相關(guān)標(biāo)簽CSS相關(guān)標(biāo)簽在HTML最頂部,但在解析到內(nèi)容標(biāo)簽( )時CSS相關(guān)標(biāo)簽尚未解析完CSS相關(guān)標(biāo)簽在HTML最底部
下面的流程是對上圖的文字版解析。讀者可將以上4種情況分別帶入到如下的渲染流程中走一遍。就能理解瀏覽器的完整渲染過程了。
【HTML】
瀏覽器收到html資源后先預(yù)掃描和
