搞定前端性能優(yōu)化問(wèn)題,原來(lái)這么簡(jiǎn)單?
性能優(yōu)化一向是前端面試中的常見(jiàn)問(wèn)題,很多同學(xué)面對(duì)性能優(yōu)化問(wèn)題時(shí)都回答的不好。所以,咱們今天就把 前端性能優(yōu)化問(wèn)題 進(jìn)行 全解析。
像什么 頁(yè)面加載慢、白屏?xí)r間長(zhǎng)、滾動(dòng)卡頓、圖片加載緩慢…… 的,一篇文章,咱們?nèi)繋Т蠹伊私庀拢?/span>
完整腦圖鎮(zhèn)樓
一、首屏加載優(yōu)化
首屏加載是指用戶打開(kāi)頁(yè)面到第一個(gè)可視內(nèi)容呈現(xiàn)出來(lái)之間的時(shí)間。它直接影響用戶對(duì)網(wǎng)站的第一印象,因此在前端性能優(yōu)化中具有最高的優(yōu)先級(jí)。
優(yōu)化首屏加載的目標(biāo)是盡可能快地把關(guān)鍵內(nèi)容展示給用戶,減少白屏?xí)r間,提升首屏體驗(yàn)。
常見(jiàn)的優(yōu)化方式包括資源按需加載、預(yù)加載關(guān)鍵資源、使用服務(wù)端渲染或靜態(tài)生成等。
1. 資源按需加載(Lazy Load)
在前端應(yīng)用中,JS、CSS、圖片等資源如果全部打包在一起加載,會(huì)極大拖慢頁(yè)面的加載速度。按需加載的核心思路是:只加載當(dāng)前頁(yè)面渲染所必須的資源,其余資源延后加載或在需要時(shí)再加載。
- JavaScript 按需加載
使用構(gòu)建工具(如 Webpack 或 Vite)時(shí),可以借助動(dòng)態(tài)導(dǎo)入(import())來(lái)實(shí)現(xiàn)路由級(jí)別或組件級(jí)別的代碼拆分(Code Splitting)。
例如,在 Vue 或 React 應(yīng)用中,每個(gè)路由頁(yè)面或大型模塊可以被拆分成獨(dú)立的 chunk 文件,只有用戶進(jìn)入該頁(yè)面時(shí)才會(huì)加載對(duì)應(yīng)的 JS 文件。 - 圖片懶加載
頁(yè)面中不在首屏展示的圖片可以使用懶加載技術(shù),延遲到滾動(dòng)進(jìn)入視口時(shí)再進(jìn)行加載??梢灾苯邮褂?nbsp;loading="lazy"屬性,無(wú)需引入第三方庫(kù)。
但是,如果想要做到更好可控性的懶加載,擇校使用IntersectionObserver來(lái)監(jiān)聽(tīng)元素是否進(jìn)入視口,從而決定是否加載圖片。 - 第三方模塊按需引入
大型庫(kù)如 Lodash、Moment 等可以按需導(dǎo)入,例如使用lodash-es代替整個(gè)lodash。日期處理可以使用dayjs替代體積龐大的moment。這類(lèi)優(yōu)化通??梢酝ㄟ^(guò) Tree Shaking 和構(gòu)建工具的配置實(shí)現(xiàn)。
2. 預(yù)加載關(guān)鍵資源
即使按需加載能夠減少首屏資源的體積,但某些資源仍然是“一定會(huì)用且必須盡早使用”的,例如首屏字體、主視覺(jué)圖、關(guān)鍵 JS 腳本等。這些資源可以通過(guò)預(yù)加載機(jī)制提前告知瀏覽器加快加載節(jié)奏。
preload<link rel="preload">用于告訴瀏覽器某個(gè)資源是高優(yōu)先級(jí)資源,應(yīng)該盡早加載。例如:
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin="anonymous">PS:as 屬性指定了資源的類(lèi)型,有助于瀏覽器進(jìn)行更好的優(yōu)先級(jí)調(diào)度。
preconnect與dns-prefetch當(dāng)頁(yè)面需要請(qǐng)求第三方資源(如 CDN、第三方接口等)時(shí),可以使用<link rel="dns-prefetch">和<link rel="preconnect">來(lái)減少 DNS 查詢(xún)和 TCP 建連的耗時(shí)。前者預(yù)解析域名,后者預(yù)建立連接。
<link rel="preconnect" crossorigin>
<link rel="dns-prefetch" >特別是在頁(yè)面初始階段要從多個(gè)域名拉取資源時(shí),這項(xiàng)優(yōu)化能有效減少網(wǎng)絡(luò)延遲。
3. 服務(wù)端渲染(SSR)或靜態(tài)站點(diǎn)生成(SSG)
現(xiàn)代單頁(yè)應(yīng)用(SPA)由于前端 JS 執(zhí)行完成之后才會(huì)渲染頁(yè)面內(nèi)容,因此在網(wǎng)絡(luò)較差或設(shè)備性能較弱的情況下容易出現(xiàn)長(zhǎng)時(shí)間白屏的現(xiàn)象。
為了解決這一問(wèn)題,可以考慮使用 服務(wù)端渲染或靜態(tài)站點(diǎn)生成 的方式,提升首屏內(nèi)容呈現(xiàn)速度。
- 服務(wù)端渲染(SSR)
SSR 的原理是前端框架(如 Vue、React)在服務(wù)器端完成首屏 HTML 的渲染并返回給客戶端,瀏覽器接收到完整的 HTML 后可立即展示頁(yè)面,之后再加載 JS 接管頁(yè)面行為。常見(jiàn)框架如 Next.js(React)、Nuxt(Vue)等都支持 SSR。SSR 可顯著減少白屏?xí)r間,提升 SEO 表現(xiàn),但會(huì)增加服務(wù)器負(fù)擔(dān)和架構(gòu)復(fù)雜度。 - 靜態(tài)站點(diǎn)生成(SSG)
SSG 會(huì)在構(gòu)建階段生成每個(gè)頁(yè)面的靜態(tài) HTML 文件并部署到 CDN。當(dāng)用戶訪問(wèn)頁(yè)面時(shí),直接從 CDN 讀取 HTML,無(wú)需等待服務(wù)器實(shí)時(shí)渲染,響應(yīng)速度極快。適合內(nèi)容基本固定的展示型網(wǎng)站,如博客、文檔站等。 - 混合渲染
現(xiàn)代框架如 Next.js、Nuxt3 支持按頁(yè)面配置渲染模式,可以為不同路由選擇 SSR、SSG 或客戶端渲染,提升靈活性。
二、資源壓縮與合并
前端頁(yè)面性能的瓶頸很大一部分來(lái)源于資源的傳輸效率,而資源壓縮與合并正是減少資源體積和請(qǐng)求次數(shù)的有效手段。
1. HTML / CSS / JS 壓縮
前端構(gòu)建工具默認(rèn)都會(huì)對(duì)代碼進(jìn)行壓縮處理,包括移除空格、注釋、換行符,以及對(duì)變量名、函數(shù)名進(jìn)行混淆,從而減少文件體積。不同的資源類(lèi)型采用不同的壓縮工具:
- JS 壓縮:常用工具包括 Terser、UglifyJS?,F(xiàn)代構(gòu)建工具如 Vite 和 Webpack 內(nèi)部默認(rèn)集成了 Terser 插件,生產(chǎn)環(huán)境自動(dòng)開(kāi)啟壓縮。
- CSS 壓縮:使用
cssnano、clean-css等工具壓縮 CSS,去除重復(fù)規(guī)則、空格、注釋等。PostCSS 的生態(tài)中也有大量 CSS 優(yōu)化插件。 - HTML 壓縮:可以使用
html-minifier工具。雖然 HTML 本身體積不大,但在 SSR 或 SSG 輸出的靜態(tài)頁(yè)面中,壓縮可以減少每次請(qǐng)求的內(nèi)容大小。
2. 圖片壓縮與格式優(yōu)化
圖片通常是頁(yè)面體積中占比最大的資源,特別是在內(nèi)容展示型或電商類(lèi)網(wǎng)站中,一張未壓縮的大圖就可能有數(shù) MB,大量圖片會(huì)嚴(yán)重拖慢頁(yè)面加載速度。
- 圖片壓縮工具:可以在構(gòu)建流程中引入
imagemin插件實(shí)現(xiàn)自動(dòng)壓縮。也可以使用一些在線壓縮工具,比如:Squoosh、TinyPNG、ImageOptim(Mac)等 - 格式優(yōu)化:傳統(tǒng)格式如 PNG、JPEG 已無(wú)法滿足現(xiàn)代 Web 的性能要求。可以使用新一代圖像格式,比如:
WebP、AVIF - SVG 圖像優(yōu)化:對(duì)于圖標(biāo)類(lèi)圖片,優(yōu)先使用 SVG。配合
svgo工具進(jìn)行壓縮,可顯著減小 SVG 文件體積。
3. 減少請(qǐng)求數(shù)
瀏覽器對(duì)于同一域名下的并發(fā)請(qǐng)求數(shù)是有限的(HTTP/1.1 下約為 6 個(gè)),如果頁(yè)面請(qǐng)求過(guò)多會(huì)被排隊(duì)執(zhí)行,影響加載速度。那么此時(shí),就可以通過(guò)資源合并可以減少請(qǐng)求數(shù)量。
需要注意的是,合并資源的策略在 HTTP/2 中發(fā)生了變化。由于 HTTP/2 支持多路復(fù)用,多個(gè)請(qǐng)求可并發(fā)傳輸,合并的必要性有所降低,但資源體積越小仍然越好,因?yàn)檎?qǐng)求數(shù)雖不再是瓶頸,傳輸大小和解析速度依舊重要。
4. 使用 CDN 分發(fā)資源
資源壓縮之后,部署方式同樣影響加載速度。將靜態(tài)資源托管在 CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))上,可以有效提升資源的下載速度,特別是面向全國(guó)或全球用戶時(shí)。
三、緩存機(jī)制優(yōu)化
緩存機(jī)制的核心目標(biāo)是“減少重復(fù)資源的網(wǎng)絡(luò)請(qǐng)求”,從而提升頁(yè)面加載速度,減輕服務(wù)器壓力。
前端常見(jiàn)的緩存方式主要包括:HTTP 緩存、本地存儲(chǔ)緩存、Service Worker 離線緩存等。
1. HTTP 緩存
HTTP 緩存是瀏覽器最基礎(chǔ)、最重要的緩存方式,主要通過(guò)響應(yīng)頭信息進(jìn)行控制。常見(jiàn)的緩存方式分為兩種:強(qiáng)緩存和協(xié)商緩存。
- 強(qiáng)緩存(強(qiáng)制使用緩存)
通過(guò)設(shè)置Cache-Control: max-age=xxx或Expires響應(yīng)頭,瀏覽器在設(shè)定時(shí)間內(nèi)不再向服務(wù)器發(fā)起請(qǐng)求,而是直接使用本地緩存。例如:
Cache-Control: max-age=31536000當(dāng)用戶在有效期內(nèi)再次訪問(wèn)頁(yè)面時(shí),請(qǐng)求不會(huì)發(fā)送,直接命中本地緩存,速度極快。
- 協(xié)商緩存(驗(yàn)證緩存)
設(shè)置ETag或Last-Modified響應(yīng)頭,瀏覽器會(huì)在下一次請(qǐng)求時(shí)攜帶If-None-Match或If-Modified-Since,服務(wù)器比對(duì)后決定資源是否更新。
如果資源未修改,返回304 Not Modified,瀏覽器繼續(xù)使用本地緩存;如果已更新,則返回新的資源。
2. 本地存儲(chǔ)緩存(localStorage / sessionStorage / IndexedDB)
localStorage永久存儲(chǔ),除非手動(dòng)清除或用戶清空瀏覽器緩存,適合存儲(chǔ)體積小、不會(huì)頻繁更新的數(shù)據(jù),如用戶設(shè)置、Token、主題配置等。sessionStorage會(huì)話級(jí)別的緩存,頁(yè)面關(guān)閉即失效。適用于需要臨時(shí)緩存的數(shù)據(jù),如一次會(huì)話中的表單步驟進(jìn)度等。IndexedDB結(jié)構(gòu)化本地?cái)?shù)據(jù)庫(kù),支持大體積數(shù)據(jù)存儲(chǔ),適合緩存復(fù)雜結(jié)構(gòu)的數(shù)據(jù),比如離線文檔、列表數(shù)據(jù)緩存、圖片緩存等。
3. Service Worker 離線緩存
Service Worker 是一種運(yùn)行在瀏覽器背后的獨(dú)立線程,配合 Cache API,可以實(shí)現(xiàn)更高級(jí)的緩存控制和離線訪問(wèn)能力,是構(gòu)建 PWA(漸進(jìn)式 Web 應(yīng)用)的核心技術(shù)之一。
四、渲染性能優(yōu)化
渲染性能是指瀏覽器將 HTML、CSS、JavaScript 等資源轉(zhuǎn)化為可視頁(yè)面的能力。即便資源加載速度足夠快,若渲染效率低下,依然會(huì)導(dǎo)致頁(yè)面卡頓、滾動(dòng)不流暢、動(dòng)畫(huà)掉幀等問(wèn)題。渲染性能優(yōu)化的目標(biāo)是減少不必要的計(jì)算、繪制和布局重排,讓瀏覽器更高效地完成頁(yè)面呈現(xiàn)工作。
常見(jiàn)的優(yōu)化方式包括控制重排重繪、使用高效的渲染方式、虛擬列表技術(shù)、避免冗余 DOM 等。
1. 減少重排與重繪
瀏覽器渲染流程中,每次修改 DOM 或 CSS 都可能引發(fā)「重排(Reflow)」或「重繪(Repaint)」,這兩者都伴隨性能開(kāi)銷(xiāo),尤其是重排最為昂貴。過(guò)多或頻繁的重排,會(huì)直接導(dǎo)致頁(yè)面掉幀、卡頓。
- 避免頻繁讀寫(xiě) DOM
JavaScript 中讀取 DOM 信息(如offsetHeight、getBoundingClientRect)后立即修改樣式,會(huì)觸發(fā)強(qiáng)制同步計(jì)算,阻塞渲染線程。應(yīng)將 DOM 讀寫(xiě)操作分批處理,避免交錯(cuò)執(zhí)行。 - 合理使用 CSS 屬性
使用transform和opacity等屬性修改樣式,可避免觸發(fā)重排,只會(huì)產(chǎn)生 GPU 層級(jí)上的合成操作,性能更優(yōu)。例如:
/* 推薦 */
.fade-in {
transition: opacity 0.3s ease;
}
.move {
transform: translateX(100px);
}
/* 不推薦 */
.resize {
width: 100px; /* 會(huì)觸發(fā)重排 */
}- 動(dòng)畫(huà)使用 requestAnimationFrame
CSS 動(dòng)畫(huà)雖然流暢,但 JS 動(dòng)畫(huà)時(shí)應(yīng)使用requestAnimationFrame來(lái)確保動(dòng)畫(huà)與瀏覽器刷新節(jié)奏同步,提升流暢性并避免資源浪費(fèi)。
2. 虛擬列表與虛擬滾動(dòng)
虛擬列表技術(shù)通過(guò)只渲染可視區(qū)域內(nèi)的內(nèi)容,大幅降低 DOM 節(jié)點(diǎn)數(shù)量。用來(lái)解決 頁(yè)面中存在大量重復(fù)結(jié)構(gòu)的 DOM(如長(zhǎng)列表、數(shù)據(jù)表格等) 的問(wèn)題
大致實(shí)現(xiàn)方案如下:
- React:
react-window、react-virtualized; - Vue:
vue-virtual-scroller; - 自研方案:基于
scrollTop和offsetHeight手動(dòng)控制渲染區(qū)間。
3. 控制 DOM 數(shù)量與嵌套層級(jí)
DOM 節(jié)點(diǎn)越多,瀏覽器構(gòu)建渲染樹(shù)的時(shí)間越長(zhǎng),布局計(jì)算復(fù)雜度越高。一般建議頁(yè)面的有效 DOM 數(shù)量控制在 1500 以?xún)?nèi),嵌套層級(jí)控制在 5 層以?xún)?nèi)。
4. 減少樣式計(jì)算與復(fù)雜選擇器
CSS 渲染過(guò)程中的「樣式計(jì)算」會(huì)遍歷 DOM 樹(shù)與樣式規(guī)則表,選擇器越復(fù)雜,匹配效率越低。
- 避免過(guò)深的選擇器,例如
.app .container .list .item .label; - 避免使用通配符
*和后代選擇器div div div; - 優(yōu)先使用類(lèi)選擇器,且盡量不要使用 ID、屬性選擇器等難以復(fù)用的選擇器。
五、性能監(jiān)控與分析
前端性能優(yōu)化不是一次性的工作,而是一個(gè)持續(xù)監(jiān)測(cè)、評(píng)估、調(diào)整的過(guò)程。只有建立起完善的性能監(jiān)控體系,及時(shí)發(fā)現(xiàn)并定位性能瓶頸,才能持續(xù)保障 Web 應(yīng)用的高可用與高體驗(yàn)。因此,性能監(jiān)控與分析在整個(gè)性能優(yōu)化閉環(huán)中扮演著至關(guān)重要的角色。
性能監(jiān)控分為兩類(lèi):開(kāi)發(fā)階段的性能分析 和 上線后的實(shí)時(shí)監(jiān)控。兩者目標(biāo)不同,但都必須具備。
1. 開(kāi)發(fā)階段:借助工具進(jìn)行性能分析
在本地開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)者可以通過(guò)瀏覽器提供的調(diào)試工具深入了解頁(yè)面加載、渲染、腳本執(zhí)行等各階段的性能表現(xiàn),從而發(fā)現(xiàn)瓶頸。常見(jiàn)的工具有:
- Chrome DevTools:最常用的瀏覽器性能分析工具,提供以下核心功能模塊:
Performance 面板:可以錄制并分析頁(yè)面的加載過(guò)程,查看幀率、JS 執(zhí)行耗時(shí)、布局重排次數(shù)、渲染瓶頸等信息。
Lighthouse 面板:可一鍵生成頁(yè)面性能報(bào)告,涵蓋性能(Performance)、可訪問(wèn)性、SEO、最佳實(shí)踐等多個(gè)維度,給出具體建議。
Network 面板:查看資源加載時(shí)間、大小、狀態(tài)碼等,判斷是否存在慢資源、請(qǐng)求阻塞、未壓縮資源等問(wèn)題。
Coverage 面板:可檢測(cè) JS/CSS 代碼的覆蓋率,找出未使用的代碼,為 Tree-Shaking 和包體積優(yōu)化提供數(shù)據(jù)支撐。
- WebPageTest / PageSpeed Insights:Google 提供的在線工具,適合分析線上站點(diǎn)的加載情況,支持不同網(wǎng)絡(luò)環(huán)境模擬,并能針對(duì) Core Web Vitals 提供評(píng)分和優(yōu)化建議。
- Core Web Vitals(核心指標(biāo)):是 Google 推出的關(guān)鍵性能指標(biāo),衡量真實(shí)用戶體驗(yàn)的關(guān)鍵維度,包括:
- LCP(Largest Contentful Paint):最大內(nèi)容繪制時(shí)間,反映首屏加載速度;
- FID(First Input Delay):首次輸入延遲,衡量交互響應(yīng)性;
- CLS(Cumulative Layout Shift):累積布局偏移,衡量頁(yè)面穩(wěn)定性。
優(yōu)秀的頁(yè)面應(yīng)該滿足以下標(biāo)準(zhǔn):
- LCP < 2.5s
- FID < 100ms
- CLS < 0.1
2. 上線階段:實(shí)時(shí)性能監(jiān)控與上報(bào)
當(dāng)頁(yè)面上線后,由于用戶設(shè)備、網(wǎng)絡(luò)、行為差異極大,僅靠本地測(cè)試無(wú)法全面掌握性能表現(xiàn)。因此需要接入性能監(jiān)控系統(tǒng),在真實(shí)用戶環(huán)境中收集關(guān)鍵性能數(shù)據(jù),以便持續(xù)追蹤和告警。
- 自定義監(jiān)控 SDK,可以通過(guò)
PerformanceObserver、performance.getEntriesByType()等 Web API 收集以下指標(biāo):
頁(yè)面加載耗時(shí)(DNS、TCP、TTFB、DomContentLoaded、Load)
資源加載耗時(shí)(圖片、腳本、字體等)
首屏渲染時(shí)間(使用打點(diǎn)或 MutationObserver 輔助采集)
首次交互時(shí)間、輸入延遲
JS 錯(cuò)誤、Promise 未處理異常、接口異常
幀率、卡頓檢測(cè)(使用 requestAnimationFrame 檢測(cè)長(zhǎng)任務(wù))
將這些數(shù)據(jù)結(jié)構(gòu)化后,統(tǒng)一上報(bào)到日志服務(wù)器,存入數(shù)據(jù)庫(kù)用于可視化展示。
- 接入第三方平臺(tái),例如:
阿里云 ARMS 前端監(jiān)控
百度 ESee / 字節(jié)跳動(dòng) Eeyes
騰訊 TARS Frontend Monitor
Sentry / LogRocket / Datadog(國(guó)外)
- 性能波動(dòng)與灰度分析:如某次發(fā)版后 LCP 從 1.8s 突然上升到 4s。此時(shí)可以結(jié)合版本號(hào)、地域、終端等維度回溯問(wèn)題來(lái)源,快速定位性能回退的根因。
3. 建立性能指標(biāo)體系與告警機(jī)制
比如:
- 在每次構(gòu)建后自動(dòng)跑 Lighthouse 分析;
- 設(shè)置性能閾值(如 LCP 超過(guò) 3s 告警);
- 頁(yè)面 JS 體積超過(guò) 250KB 即阻斷上線流程;
- 配合灰度發(fā)布與版本對(duì)比,確保性能不回退。
- 等等
除了以上 5 點(diǎn)之外,咱們還需要注意 代碼層面 的一些優(yōu)化,比如:減少代碼體積,邏輯盡量清晰 等等。不過(guò)這一部分的內(nèi)容更多會(huì)因人而異,所以這里就不去展開(kāi)說(shuō)啦!


























