掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文會對web頁面的全鏈路進行完整的講解并針對每一步找到能做的性能優(yōu)化點,本文的目標是極致的性能優(yōu)化。

成都創(chuàng)新互聯(lián)公司咨詢熱線:18980820575,為您提供成都網(wǎng)站建設(shè)網(wǎng)頁設(shè)計及定制高端網(wǎng)站建設(shè)服務(wù),成都創(chuàng)新互聯(lián)公司網(wǎng)頁制作領(lǐng)域十載,包括成都混凝土攪拌機等多個領(lǐng)域擁有多年建站經(jīng)驗,選擇成都創(chuàng)新互聯(lián)公司,為網(wǎng)站錦上添花。
因為針對性能優(yōu)化,能做的點會特別特別的多,覆蓋著整個互聯(lián)網(wǎng)的訪問流程,因此此文章的內(nèi)容會比較多且雜,筆者會盡量對內(nèi)容進行分類講解。
本文的大致流程為先講理論知識,比如如何評價一個頁面的性能好與不好、如果獲取性能指標,如何使用各種性能相關(guān)工具,瀏覽器如何獲取并渲染頁面。筆者認為這些都是基礎(chǔ),只有了解了這些基礎(chǔ)才能開始考慮如何去優(yōu)化。
接下來我們會進入性能優(yōu)化環(huán)節(jié),在這個環(huán)節(jié)我會詳細講解在頁面的整個流程中,哪些地方可以做哪些優(yōu)化。
1.用戶輸入
2.卸載原頁面并重定向到新頁面
3.處理Service Worker
4.網(wǎng)絡(luò)請求
5.服務(wù)端響應
6.瀏覽器渲染詳細流程
我們需要知道瀏覽器是如何渲染一個頁面的,我們才能知道如何對頁面進行性能優(yōu)化,所以這里我們對一些基礎(chǔ)知識進行講解
瀏覽器有多種進程,其中最主要的5種進程如下
圖1
用戶在 瀏覽器進程 輸入并按下回車健后,瀏覽器判斷用戶輸入的url是否為正確的url,如果不是,則使用默認的搜索引擎將該關(guān)鍵字拼接成url。
然后瀏覽器會將現(xiàn)有頁面卸載掉并重定向到用戶新輸入的url頁面,也就是圖中【Process Unload Event】和【Redirect】流程。
此時瀏覽器會準備一個 渲染進程 用于渲染即將到來的頁面,和一個 網(wǎng)絡(luò)進程 用于發(fā)送網(wǎng)絡(luò)請求。
如果當前頁面注冊了Service Worker那么它可以攔截當前網(wǎng)站所有的請求,進行判斷是否需要向遠程發(fā)送網(wǎng)絡(luò)請求。也就是圖中【Service Worker Init】與【Service Worker Fecth Event 】步驟
如果不需要發(fā)送網(wǎng)絡(luò)請求,則取本地文件。如果需要則進行下一步。
OSI網(wǎng)絡(luò)七層模型:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會話層、表示層、應用層
在實際應用中物理層、數(shù)據(jù)鏈路層被統(tǒng)稱為物理層,會話層、表示層、應用層被統(tǒng)稱為應用層,所以實際使用時通常分為4個層級
【物理層】>【網(wǎng)絡(luò)層(IP)】>【傳輸層(TCP/UDP)】>【應用層(HTTP)】
也就是圖中【HTTP Cache】、【DNS】、【TCP】、【Request】、【Response】步驟
圖2
瀏覽器會拿著url通過 網(wǎng)絡(luò)進程 進行如下步驟
HTTP/2.0
多路復用
:
hpack
HTTP/3.0 使用UDP實現(xiàn),在UDP上一層加入一層 QUIC 協(xié)議,解決了TCP協(xié)議中的隊頭阻塞問題。
在 4.網(wǎng)絡(luò)請求 第 6 步中,服務(wù)器收到HTTP請求后需要根據(jù)請求信息來進行解析,并返回給客戶端想要的數(shù)據(jù),這也就服務(wù)端響應。
服務(wù)端可以響應并返回給客戶端很多種類型的資源,這里主要介紹 html 類型
目前前端處理服務(wù)端響應html請求主要分為SSR服務(wù)端渲染與CSR客戶端渲染,CSR就是返回一個空的HTML模版,然后瀏覽器加載js后通過js動態(tài)渲染頁面。SSR是服務(wù)端在接受到請求時事先在服務(wù)端渲染好html返回給客戶端后,客戶端再進行客戶端激活。
在打開一個站點的首屏頁的完整鏈路中,使用SSR服務(wù)端渲染時的速度要遠大于CSR客戶端渲染,并且SSR對SEO友好。所以對于首屏加載速度比較敏感或者需要優(yōu)化SEO的站點來說,使用SSR是更好的選擇。
瀏覽器渲染詳細流程主要在 4.網(wǎng)絡(luò)請求 中的地 7 步。瀏覽器下載完 html 內(nèi)容后進行解析何渲染頁面的流程。
渲染流程分為4種情況,
下面的流程是對上圖的文字版解析。讀者可將以上4種情況分別帶入到如下的渲染流程中走一遍。就能理解瀏覽器的完整渲染過程了。
瀏覽器收到html資源后先預掃描 和 并加載對應資源
對HTML字符串從上到下逐行解析,每解析完成一部分都會拿著解析結(jié)果進入下一步驟
css 相關(guān)標簽跳過此步驟
如果當前解析結(jié)果為
相關(guān)標簽,則生成DOM樹( window.document )后進入下一步。如果當前解析結(jié)果為 相關(guān)標簽且并且沒有添加異步屬性,則先停止【HTML Parser】的進行,等待 資源加載完成后,然后按照以下2種情況處理,當處理完成后便停止當前 標簽后續(xù)步驟的執(zhí)行,并繼續(xù)進行新標簽【HTML Parser】步驟的解析
如果當前解析結(jié)果為 css 相關(guān)標簽,則等待其CSS資源加載完成,同時繼續(xù)進行下一行的【HTML Parser】
當CSS資源加載完畢后,對CSS從上到下逐行解析
當CSS解析完畢后,生成CSS規(guī)則樹,也叫CSSOM,也就是 window.document.styleSheets
根據(jù)DOM樹與CSS規(guī)則樹計算出每個節(jié)點的具體樣式。
分為兩種情況
如果HTML從未解析到過 css 相關(guān)標簽則使用HTML默認樣式,如果已經(jīng)解析到過 css 相關(guān)標簽則阻塞等待 css 標簽也完成【Attachment】步驟后才進入下一步。
則需要根據(jù)是否在之前已經(jīng)渲染過CSS資源中對應的DOM節(jié)點,如果已經(jīng)渲染過則需要重繪。如果未渲染過任何相關(guān)DOM節(jié)點則此步驟為最后一步。
生成渲染樹,在此階段已經(jīng)可以將具體的某個
與對應的CSS樣式對應起來了。有了渲染樹后瀏覽器就能根據(jù)當前瀏覽器的狀態(tài)計算出某個DOM節(jié)點的樣式、大小、寬度、是否獨占一行等信息。計算完成后把一些不需要顯示出來的節(jié)點在渲染樹中刪掉。如 display: none 。通過渲染樹進行分層(根據(jù)定位屬性、透明屬性、transform屬性、clip屬性等)生成圖層樹。
繪制所有圖層,并轉(zhuǎn)交給合成線程來最最終的合并所有圖層的處理。
最終生成頁面并顯示到瀏覽器上
瀏覽器在渲染完頁面之后還需要不間斷的處理很多內(nèi)容的,比如動畫、用戶事件、定時器等。因此當瀏覽器渲染完頁面后,還會在之后的每一幀到來時執(zhí)行以下的流程。
了解完瀏覽器渲染原理,我們還需要知道根據(jù)哪些指標才能判斷一個頁面性能的好壞,在Chrome中這些指標應該怎么獲取。以及Chrome都為我們提供了哪些性能相關(guān)的工具,如何使用。
Performance既是一個Chrome工具,可用于性能檢測。
同樣又是一套JS API,可在Chrome中執(zhí)行。
打開Chrome調(diào)試面板選擇 Performance ,中文版為 性能 ,點擊刷新按鈕,Performance會刷新并錄制當前頁面,然后我們就可以在面板中看到如下的各種性能相關(guān)細節(jié)。
js中存在Performance API,可用于性能檢測,具體如下
接下來我們來了解一下目前常用的性能指標,并且我們需要知道其中一些關(guān)鍵指標如何用Performance API獲取。
TTFB(Time To First Byte) : 從發(fā)送請求到數(shù)據(jù)返回第一個字節(jié)所消耗的時間
const { responseStart, requestStart } = performance.timing
const TTFB = responseStart - requestStart
FP (First Paint) 首次繪制 : 第一個像素繪制到頁面上的時間
const paint = performance.getEntriesByType('paint')
const FP = paint[0].startTime
FCP (First Contentful Paint) 首次內(nèi)容繪制 標記瀏覽器渲染來自 DOM 第一位內(nèi)容的時間點,該內(nèi)容可能是文本、圖像、SVG 甚至 元素.
const paint = performance.getEntriesByType('paint')
const FCP = paint[1].startTime
FMP(First Meaningful Paint) 首次有效繪制 : 例如,在 YouTube 觀看頁面上,主視頻就是主角元素.
圖片可以沒加載完成,但整體的骨架已經(jīng)加載完成了。
1秒內(nèi)完成FMP的概率超過80%,那就代表這個網(wǎng)站是一個性能較好的網(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 (Time to Interactive) 可交互時間 : DOM樹構(gòu)建完畢,可以綁定事件的時間
const { domInteractive, fetchStart } = performance.timing
const TTI = domInteractive - fetchStart
LCP (Largest Contentful Paint) 最大內(nèi)容渲染 : 代表在viewport中最大的頁面元素加載的時間. LCP的數(shù)據(jù)會通過PerformanceEntry對象記錄, 每次出現(xiàn)更大的內(nèi)容渲染, 則會產(chǎn)生一個新的PerformanceEntry對象.(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 (DomContentloaded) : 當 HTML 文檔被完全加載和解析完成之后,DOMContentLoaded 事件被觸發(fā),無需等待樣式表、圖像和子框架的完成加載
const { domContentLoadedEventEnd, fetchStart } = performance.timing
const DCL = domContentLoadedEventEnd - fetchStart
L (onLoad) , 當依賴的資源(圖片、文件等), 全部加載完畢之后才會觸發(fā)
const { loadEventStart, fetchStart } = performance.timing
const L = loadEventStart - fetchStart
FID (First Input Delay) 首次輸入延遲 : 指標衡量的是從用戶首次與您的網(wǎng)站進行交互(即當他們單擊鏈接,點擊按鈕等)到瀏覽器實際能夠訪問之間的時間
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 (Total Blocking Time) 頁面阻塞總時長 : TBT匯總所有加載過程中阻塞用戶操作的時長,在FCP和TTI之間任何long task中阻塞部分都會被匯總
CLS (Cumulative Layout Shift) 累積布局偏移 : 總結(jié)起來就是一個元素初始時和其hidden之間的任何時間如果元素偏移了, 則會被計算進去, 具體的計算方法可看這篇文章 https://web.dev/cls/
SI (Speed Index) : 指標用于顯示頁面可見部分的顯示速度, 單位是時間
獲取代碼未使用占比
獲取性能報告并查看推薦優(yōu)化項
可以在本地安裝命令行工具來使用,也可以通過Chrome來使用。
命令行方式使用
npm install -g lighthouse
lighthouse --view https://m.baidu.com
在Chrome中使用
能獲取網(wǎng)絡(luò)請求的時間消耗細節(jié),可以根據(jù)耗時來決定優(yōu)化策略。優(yōu)先優(yōu)化耗時最長的
【正在排隊】網(wǎng)絡(luò)請求隊列的排隊時間
【已停止】阻塞住用于處理其他事情的時間
【DNS查找】用于DNS解析IP地址的時間
【初始連接】創(chuàng)建TCP連接時間
【SSL】用于SSL協(xié)商的時間
【已發(fā)送請求】用于發(fā)送請求的時間
【等待中】請求發(fā)出至接收響應的時間也可以理解為服務(wù)端處理請求的時間
【下載內(nèi)容】下載響應的時間
瀏覽器會根據(jù)資源的類型決定優(yōu)先請求哪些資源,優(yōu)先級高的請求能夠優(yōu)先被加載。
右擊此處勾選優(yōu)先級可打開優(yōu)先級功能,在請求中便可看到網(wǎng)絡(luò)請求的優(yōu)先級
不同資源類型的優(yōu)先級排序如下
【最高】html、style
【高】font、fetch、script
【低】image、track
【58個請求】網(wǎng)頁一共多少個請求
【6.9 MB 項資源】網(wǎng)頁資源一共6.9MB大小
【DOMContentLoaded:454 毫秒】DOM加載完畢的時長
【加載時間:1.02 秒】onload完畢的時長
上面我們分別講解了進程與線程、瀏覽器打開一個頁面的完整過程、瀏覽器處理每一幀時的流程、Chrome性能相關(guān)的各種工具以及性能相關(guān)的各種指標。以上內(nèi)容都掌握之后我們再考慮性能優(yōu)化遍有了思路,我們在頁面展示的任意一個步驟中對其進行優(yōu)化都能對整個網(wǎng)頁的展示性能產(chǎn)生影響。
下面列出了一個頁面能優(yōu)化的所有內(nèi)容,讀者可根據(jù)自己的業(yè)務(wù)情況結(jié)合性能工具來做適合自己的優(yōu)化方式。
合并JS、合并CSS、合理內(nèi)嵌JS和CSS、使用雪碧圖
使用強制緩存可以不走網(wǎng)絡(luò)請求,直接走本地緩存數(shù)據(jù)來加載資源。
使用協(xié)商緩存可以減少數(shù)據(jù)傳輸,當不需要更新數(shù)據(jù)時可通知客戶端直接使用本地緩存。
HTTP/2.0使用同一個TCP連接來發(fā)送數(shù)據(jù),他把多個請求通過二進制分貞層實現(xiàn)了分貞,然后把數(shù)據(jù)傳輸給服務(wù)器。也叫 多路復用 ,多個請求復用同一個TCP連接。
HTTP/2.0會將所有以 : 開頭的請求頭做一個映射表,然后使用 hpack 進行壓縮,使用這種方式會使請求頭更小。
服務(wù)器可主動推送數(shù)據(jù)給客戶端。
301、302 重定向會降低響應速度
DNS請求雖然占用的帶寬較少,但會有很高的延遲,由其在移動端網(wǎng)絡(luò)會更加明顯。
使用dns-prefetch可以對網(wǎng)站中使用到的域名提前進行解析。提高資源加載速度。
通過dns預解析技術(shù)可以很好的降低延遲,在訪問以圖片為主的移動端網(wǎng)站時,使用DNS預解析的情意中下頁面加載時間可以減少5%。
在HTTP/1.1中,一個域名同時最多創(chuàng)建6個TCP連接,將資源放在多個域名下可提高請求的并發(fā)數(shù)
靜態(tài)資源全上CDN,CDN能非常有效的加快網(wǎng)站靜態(tài)資源的訪問速度。
gzip壓縮、html壓縮、js壓縮、css壓縮、圖片壓縮
contenthash可以根據(jù)文件內(nèi)容在文件名中加hash,可用于瀏覽器緩存文件,當文件沒有改變時便直接取本地緩存數(shù)據(jù)
preload預加載、prefetch空閑時間加載
兩者都不會阻塞 onload 事件, prefetch 會在頁面空閑時候再進行加載,是提前預加載之后可能要用到的資源,不一定是當前頁面使用的, preload 預加載的是當前頁面的資源。
Document
如上代碼,預加載了css但并沒有使用。瀏覽器在頁面 onload 完成一段時間后,發(fā)現(xiàn)還沒有引用預加載的資源時,瀏覽器會在控制臺輸出下圖的提示信息
preload和prefetch可根據(jù)資源類型決定資源加載的優(yōu)先級,詳細優(yōu)先級如代碼
Document
當通過JS或者其他任意方式修改DOM后,瀏覽器會進入如下流程
【JS通過API修改DOM】>【計算樣式】>【布局(重排)】>【繪制(重繪)】>【合成】
Reflow 重排 :重排在Chrome Performance中叫做布局,通常添加或刪除元素、修改元素大小、移動元素位置、獲取位置信息都會觸發(fā)頁面的重排,因為重排可能會改變元素的大小位置等信息,這樣的改變會影響到頁面大量其它元素的大小位置信息,會耗費掉大量的性能,所以在實際應用中我們應該盡可能的減少重排
Repaint 重繪 :重繪在Chrome Performance中叫做繪制,通常樣式改變但沒有影響位置時會觸發(fā)重繪操作,重繪性能還好,但我們也需要盡量減少重繪,如果需要做一些動畫,我們盡量使用CSS3動畫,CSS3動畫只需要在初始化時繪制一次,之后的動畫都不會觸發(fā)重繪操作。
在同一個函數(shù)內(nèi),修改元素后又獲取元素的位置時會觸發(fā)強制同步布局,影響渲染性能
強制同步布局會使js強制將【計算樣式】和【布局(重排)】操作提前到當前函數(shù)任務(wù)中,這樣會導致每次運行時執(zhí)行一次【計算樣式】和【重排】,這樣一定會影響頁面渲染性能,而正常情況下【計算樣式】和【重排】操作會在函數(shù)結(jié)束后統(tǒng)一執(zhí)行。
Document
在函數(shù)運行時執(zhí)行了10次【計算樣式】和【重排】
反復觸發(fā)強制同步布局也叫 布局抖動
網(wǎng)頁題目:Web頁面全鏈路性能優(yōu)化指南
標題URL:http://uogjgqi.cn/article/djcjhje.html

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流