前端性能优化
前端性能优化
[TOC]
一、资源加载优化
1.减少HTTP请求
2.压缩资源
3.使用CDN
4.图片懒加载(Lazy Loading)
5.预加载与预取
二、渲染性能优化
1.减少重排(Reflow)与重绘(Repaint)
2.使用虚拟DOM(React/Vue)
三、JavaScript优化
1.代码分割(Code Splitting)、按需加载
2.Tree Shaking:移除未使用的代码
3.防抖(Debounce)与节流(Throttle):限制高频事件(如滚动、输入、购物车数量点击)的处理频率
4.避免内存泄漏:及时解绑事件监听器、清理定时器、闭包引用
四、缓存策略
1.HTTP缓存:设置合理的Cache-Control/ETag
2.Service Worker(PWA),实现离线缓存、资源拦截
3.本地存储优化:合理使用localStorage
五、现代Web技术
1.使用现代格式:图片:WebP替代JPEG/PNG。脚本:使用原生ES Module减少打包体积
2.启用HTTP/2或HTTP/3:多路复用、头部压缩等特性提升加载效率
3.字体优化:使用font-display:swap避免文字不可见
六、监控与分析
1.性能指标监控

LCP(最大内容绘制)、CLS(累计布局偏移)、FCP(首个内容绘制)
使用Lighthouse、WebPageTest、Chrome DevTools分析
Web.dev 提高Core Web Vitals 最有效的方法
https://web.dev/articles/top-cwv?hl=zh-cn
1.LCP(最大内容绘制Largest Contentful Paint)
概念:从用户首次导航到网页,到“视口内可见的最大图片、文本块或视频”渲染出来的事件,这个“视口内可见的最大图片、文本块或视频”元素也被称为LCP元素。
1.LCP元素识别错误
原本LCP元素应该是Banner大图,但是弹窗被当成LCP元素。
原因:
Banner大图实际上是由“CSS渐变背景色+几张小图”组合而成,几张小图都没有订阅弹窗里的背景图大,导致订阅弹窗内的背景图被当成LCP元素。
解决:
1.去除Banner中的CSS背景色并替换成真实的图片(webp)
2.在现有的背景色的情况下,额外加一张透明度为0.001的大图,覆盖整个banner,即可被识别成LCP元素。
2.LCP分段分析
LCP元素需要尽可能小,便于网络加载,因此需要压缩图片。
除此之外,出现LCP分数低的问题,一般是LCP元素“开始加载”的时间点过于靠后,即“资源加载延迟”过久。
利用性能分析工具,可以得到LCP元素的加载情况。

2.CLS(布局偏移量Cumulative Layout Shift)
(布局偏移量,偏移越大分数越低)
概念:网页加载时,若元素造成DOM重排则会增加布局偏移量。某个人元素长宽或者边距突然变大、变小、布局排列方式改变等等,可能会增加布局偏移量。
CLS是跑分成绩中占比较大但是最容易优化的一项,所以尽可能拿满分。
常见的布局偏移场景
(1)没有长宽属性的图片
img图片一定需要设置width、height属性,提前告知浏览器这张图片大小比例。如果缺少这两个属性,图片加载之前渲染的高度会一直是0。
(2)轮播图尚未初始化
一般来讲为了更好性能,我们会让轮播图推迟初始化(网页文档加载之后才初始化轮播图),但轮播图初始化之前,轮播图会处于错位状态。

这种情况下需要为该模块轮播图额外编写“未初始化轮播图时”的样式
代码示例:
Swiper.js 用 :not(.swiper-initialized) 选择器匹配未初始化的轮播图,
1 | .section-name .swiper:not(.swiper-initialized) { |
slick.js 用 :not(.slick-initialized) 选择器匹配未初始化的轮播图,
1 | .section-name .xxxxxx:not:not(.slick-initialized) { |
3.CSS或JavaScript动画
产生动画的元素会引起其他元素位移,引起DOM重排。建议使用CSS transform进行变换。
4.推迟加载CSS文件
适当推迟加载CSS有助于网页提升加载速度。但如果推迟的CSS引起布局变化的样式则可能会增加布局偏移。
分析布局偏移
Pagespeed报告->切换到CLS子项报告,标明出现大幅度布局偏移的元素和对应分数。
1
利用Chrome、Edge等浏览器开发工具(F12)中的性能分析工具。
Layout shifts一栏即为网页加载时间轴中发生的布局偏移,偏移量越大则方块越大

点击防空可以查看发生偏移的DOM元素和导致偏移的因素


3.FCP(首屏加载时间First Contentful Paint)
概念:首屏时间(First Contentful Paint):指浏览器从相应用户输入网络地址,到网页任何一部分内容呈现在屏幕上的时间。一般网页绘制出的第一个内容是导航栏、公告栏,所以优化FCP第一步就是优化导航栏/公告栏之前的代码。
要优化FCP,首先要分析FCP截止前后帧的区别
正常情况:FCP前一帧是全白屏,下一帧只渲染出导航栏,后续帧依次渲染各个模块

异常情况:FCP前一帧是全白屏,下一帧将全部内容一起显示出来,一般是全部内容透明度0直至网页加载完成再解除透明度0所导致的。

分析FCP各部分耗时
在性能分析工具中,找到FCP截止线,展开网络分析哪些资源阻塞了网页加载,展开主要分析哪些脚本函数影响了网页加载。

常用优化手段
1.移除、推迟加载CSS/JS资源
对不常用的CSS、JS,应移除只在需要用到的页面中引入,按需加载。
对于非重要的资源,以及较大的CSS、JS,应推迟加载,如Swiper.js lottie.js plyr.js等。
推迟方式:
外联 CSS 资源添加 media="print" onload="this.media='all'属性
外联JS资源添加defer属性
<script src="{{ 'global.js' | asset_url }}" defer="defer"></script>
通过DOMContentLoaded事件,可以使代码在网页DOM结构加载完成后执行
window.addeventListener('DOMContentLoaded', function() { // ... });
4.INP(交互至绘制延迟Interaction to Next Paint)
交互到下一次绘制时间/交互相应延迟/交互至绘制延迟
1.经常使用yield来拆分长任务
当任务时长超过50ms时,就会成为长任务。冗长任务会造成问题,因为可能会阻止主线程快速响应用户互动。
2.避免不必要的JavaScript
使用Chrome DevTools中覆盖率工具查找脚本未使用代码,通过缩减启动期间所需资源大小,确保网页花在解析和编译代码的时间上更少,从而提供更顺畅的初始用户体验。
给未使用的JavaScript进行代码分块,在使用的时候再进行调用。
3.避免进行大规模渲染更新
在进行大型渲染期间,网站会对用户互动做出相应的速度会变得更慢。
重新整理JavaScript中的DOM读写操作,避免强制布局和布局抖动。
使DOM大小保持小巧。DOM大小与布局工作强度是相关的。当渲染程序必须更新非常大的DOM布局时,重新计算其布局工作量可能会大幅增加。
使用CSS容器来延迟渲染屏幕外DOM的内容。
5.TTFB(首字节时间Time To First Byte)
TTFB = 网络延迟 + 服务器处理时间
具体包括以下阶段:
DNS查询(如未缓存)
TCP连接建立(三次握手)
TLS协商(如果是HTTPS)
发送HTTP请求
服务器处理请求(如查询数据库、渲染页面等等)
服务器开始返回第一个字节
尽可能在距离用户地理位置最近的地方传送内容。
缓存该内容以便在近期再次受到请求时能够快速传送。
最佳方式是使用CDN。CDN会将您的资源分发到全球各地的边缘服务器,从而缩短这些资源通过线路传输到用户的距离。
6.TBT(总阻塞时间Total Blocking Time)
网站应尽力在平均移动硬件上测试将总阻塞时间控制在200毫秒以内。
总阻塞时间 (TBT) 指标用于衡量在首次内容渲染 (FCP) 之后,主线程处于阻塞状态的总时长,在此期间,主线程处于阻塞状态的时间够长,足以阻止输入响应。
只要有长任务(在主线程上运行超过 50 毫秒的任务),主线程就会被视为“阻塞”。之所以说主线程被“阻塞”,是因为浏览器无法中断正在进行的任务。因此,如果用户在长时间任务执行到一半时确实与网页互动,浏览器必须等待任务完成才能做出响应。
如何缩短TBT
一般来说,提高网站的TBT需要减少阻塞脚本的数量,这意味着要么优化脚本以减少阻塞,要么减少脚本的总量。
缩短JavaScript的执行时间,最大限度减少主线程工作,保持较低的请求数量和较小的传输大小。
2.真实用户监控(RUM)
收集真实设备上的性能数据(如通过Sentry、Google Analytics)
七、框架特定优化(以React为例)
使用React.memo、useMemo、useCallback 避免重复渲染
使用Suspense + lazy实现组件懒加载
避免在render中创建新对象/函数
