前端性能优化是每个前端工程师都需要关注的话,题也是提升用户体验的关键一个网站的性能好坏直接影响用户的留存和转化研究表明页面加载时间每增加1秒转化率就会下降7%所以性能优化不是锦上添花而是必须做的事情。
我做前端开发已经有几年了做过很多项目的性能优化踩了不少坑也积累了一些经验今天想系统地总结一下前端性能优化的最佳实践从网络加载渲染运行四个维度梳理性能优化的方法和技巧希望能帮大家建立系统的性能优化知识体系。
一、性能优化的原则和指标
在讲具体的优化方法之前,先说说性能优化的原则和指标这是性能优化的基础。
性能优化的原则:
- 数据驱动:性能优化不能凭感觉要用数据说话先测量找到瓶颈再针对性优化优化后再测量验证效果不要盲目优化。
- 用户体验优先:性能优化的目标是提升用户体验不是追求数字好看要关注用户感知的性能,比如首屏时间可交互时间而不是只看加载完成时间。
- 性价比优先:性能优化要考虑投入产出比优先优化影响大成本低的点不要为了提升几毫秒花大量时间和精力过度优化。
- 持续优化:性能优化不是一次性的工作是持续的过程项目迭代会引入新的性能问题需要持续监控和优化。
关键性能指标:
- 首屏时间(First Paint / First Contentful Paint):页面第一次绘制的时间用户第一次看到页面内容的时间这是用户感知最明显的指标。
- 可交互时间(Time to Interactive):页面可以响应用户交互的时间用户能点击按钮输入文字的时间这比首屏时间更重要,因为用户要的是能用不是能看。
- 总加载时间(Load Time):页面所有资源加载完成的时候,间onload事件触发的时间。
- 文件大小:HTMLCSSJS图片等资源的大小gzip后的大小这是,影响加载时间的关键因素。
- 请求数:页面加载的HTTP请求数量请求数越多加载越慢特别是,HTTP/1.1下请求数影响很大。
- 帧率(FPS):页面动画和交互的流畅度60fps是,流畅的标准低于30fps用户会觉得卡顿。
二、网络优化
网络是前端性能的第一个环节资源从服务器传输到浏览器的速度直接影响页面加载时间。
1. 使用CDN:
CDN(内容分发网络)能把资源缓存到离用户最近的节点用户访问时从最近的节点获取资源大大减少网络延迟提升加载速度。
- 静态资源(JSCSS图片字体视频等等)都应该放到CDN上。
- 选择覆盖广节点多的CDN服务商确保不同地区的用户都能快速访问。
- 配置合理的缓存策略静态资源长缓存HTML短缓存。
2. 启用HTTP/2:
HTTP/2支持多路复用头部压缩服务器推送等等特性能显著提升页面加载速度特别是资源多的页面。
- 服务器配置支持HTTP/2需要HTTPS支持。
- HTTP/2下不需要做域名分片(domain sharding)因为多路复用已经解决了并发限制的问题域名分片反而可能影响性能。
- 可以用服务器推送(Server Push)把关键资源主动推给浏览器减少请求往返,但是要谨慎使用避免推送不需要的资源。
3. 启用gzip/Brotli压缩:
文本资源(HTMLCSSJSJSONSVG等等)压缩后体积能减少60-80%大大减少传输时间。
- 服务器配置开启gzip压缩所有文本资源都压缩。
- 如果浏览器支持Brotli优先用Brotli压缩比gzip压缩率更高体积更小。
- 图片视频等二进制资源已经是压缩格式不需要再gzip压缩压缩效果不好还浪费CPU。
4. 减少DNS查找:
DNS解析需要时间一般20-120毫秒减少DNS查找能减少页面加载时间。
- 尽量少用不同的域名资源尽量放在同一个域名,或者少数几个域名。
- 用DNS预解析(dns-prefetch)提前解析第三方域名减少DNS解析时间。
<link rel="dns-prefetch" href="//api.example.com">5. 减少重定向:
重定向会增加额外的HTTP请求和往返延迟影响性能尽量避免。
- 不要用重定向来处理URL规范化尽量在服务器配置,或者路由层面处理。
- 如果必须重定向用301永久重定向不要用302临时重定向301能被缓存。
- 避免多重重定向(A -> B -> C)尽量直接重定向到最终URL。
三、加载优化
加载优化是减少资源体积和请求数让浏览器更快加载资源。
1. 资源压缩和合并:
- JS压缩:用TerserUglifyJS等工具压缩JS去掉空格注释缩短变量名能减少30-50%的体积。
- CSS压缩:用cssnanoPostCSS等工具压缩CSS去掉空格注释合并相同的规则能减少20-30%的体积。
- HTML压缩:用html-minifier等工具压缩HTML去掉空格注释能减少10-20%的体积。
- 合并文件:HTTP/1.1下合并JSCSS文件减少请求数,但是HTTP/2下不需要过度合并,因为多路复用已经解决了并发问题过度合并反而影响缓存和并行加载。
2. 图片优化:
图片一般占网页体积的50%以上图片优化是性能优化的重点。
- 选择合适的格式:照片用JPEG或者WebP图标和透明图片用PNG或者,WebP简单的图形用SVG动画用WebP或者GIF(WebP更好)。
- 压缩图片:用TinyPNGImageOptimimagemin等工具压缩图片在,不明显影响质量的前提下减少体积能减少30-70%。
- 使用WebP:WebP格式比JPEG和PNG体积小25-35%支持有损和,无损压缩支持透明和动画现代浏览器都支持用picture标签做降级。
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="image">
</picture>- 响应式图片:用srcset和sizes根据屏幕分辨率和,显示尺寸加载合适大小的图片不要在手机上加载2000px宽的图片。
<img srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
src="image-800.jpg" alt="image">- 图片懒加载:首屏以下的图片懒加载滚动到可视区域再加载减少首屏请求数和加载时间用Intersection Observer实现,或者用loading="lazy"原生属性。
- 雪碧图:小图标合并成雪碧图(CSS Sprite)减少请求数,但是HTTP/2下雪碧图的必要性降低了可以用SVG图标,或者图标字体替代。
- 字体图标:小图标用字体图标(Font Awesome等等)或者,SVG比图片体积小还能任意缩放改色。
3. 字体优化:
字体文件一般比较大加载慢会导致文字闪烁(FOIT/FOUT)需要优化。
- 字体子集化:只包含用到的字符减少字体文件体积,比如中文字体几万个字符,但是实际用到的可能,只有几千个子集化后体积能减少很多。
- 使用woff2格式:woff2比woffttfotf体积小30%现代浏览器都支持用@font-face做降级。
- font-display: swap:设置font-display: swap字体加载完之前,用降级字体显示加载完再切换避免文字不显示(FOIT)。
- 预加载关键字体:用<link rel="preload">预加载关键字体让浏览器提前加载减少字体加载时间。
- 避免使用太多字体:一个网站不要用太多不同的字体和,字重尽量少用减少字体文件数量和体积。
4. 代码分割和懒加载:
代码分割能把代码分成多个文件按需加载减少首屏加载体积。
- 路由级分割:单页应用(SPA)按路由分割代码每个页面的代码单独打包首屏只加载当前页面的代码其他页面按需加载用动态import(import())实现。
- 组件级分割:大的组件,或者不常用的组件(弹窗抽屉等等)单独分割按需加载减少首屏代码。
- 第三方库分割:第三方库(vendor)单独打包和业务代码分开业务代码变化不影响第三方库的缓存用Webpack的splitChunks实现。
- JS懒加载:不急需的JS代码懒加载,比如评论模块广告模块等等用户滚动到,或者点击时再加载。
- CSS懒加载:不首屏的CSS懒加载,比如打印样式移动端样式等等用media属性,或者JS动态加载。
5. 预加载和预获取:
预加载和预获取能让浏览器提前加载资源提升加载速度。
- preload:预加载当前页面需要的关键资源(字体CSSJS图片等等)让浏览器提前加载优先级高。
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>- prefetch:预获取下一个页面可能需要的资源优先级低浏览器空闲时加载,比如用户可能点击的下一个页面的资源。
<link rel="prefetch" href="next-page.js">- preconnect:提前建立和第三方域名的连接(DNSTCPTLS)减少请求时的连接时间。
<link rel="preconnect" href="//api.example.com">- 不要滥用:preload和prefetch不要滥用只预加载真正需要的资源,否则会浪费带宽影响性能。
四、渲染优化
渲染优化是让浏览器更快渲染页面减少白屏时间和卡顿。
1. 关键CSS内联:
首屏需要的CSS(Critical CSS)内联到HTML的<style>标签里首屏不用等CSS文件加载就能渲染剩下的CSS异步加载减少白屏时间。
- 用CriticalPenthouse等工具提取首屏CSS。
- 内联的CSS不要太大控制在14KB以内(TCP慢启动的初始拥塞窗口大概14KB)确保第一个TCP包能包含HTML和内联CSS。
- 非关键CSS用异步加载(media="print"onload切换,或者JS动态加载)。
2. CSS放在头部JS放在底部:
- CSS放在<head>里让浏览器尽早加载CSS避免无样式内容闪烁(FOUC)。
- JS放在</body>前,或者加defer/async避免JS阻塞页面渲染减少白屏时间。
- defer:异步加载DOM解析完后按顺序执行适合依赖DOM的脚本。 - async:异步加载加载完就执行执行顺序不确定适合不依赖DOM和,其他脚本的独立脚本。
3. 减少重排重绘:
重排(Reflow/Layout)和重绘(Repaint)会影响渲染性能导致页面卡顿要尽量减少。
- 批量修改DOM:不要逐个修改DOM样式先把元素display:none或者,用DocumentFragment修改完再显示只触发一次重排。
- 用transform和opacity做动画:这两个属性不会触发重排只触发合成(Composite)性能好不要用topleftwidthheight等属性做动画会触发重排。
- 用will-change提示浏览器:对要做动画的元素设置will-change: transform提示浏览器提前优化,但是不要滥用,否则会占用更多内存。
- 避免频繁读取布局属性:读取offsetTopoffsetLeftscrollTop等属性会强制浏览器同步计算布局导致性能问题尽量缓存这些值不要在循环里频繁读取。
- 用requestAnimationFrame:DOM修改和动画放到requestAnimationFrame里和浏览器刷新同步避免卡顿。
4. 图片尺寸设置:
给图片设置width和height或者aspect-ratio避免图片加载后页面重排(内容跳动)提升用户体验和,Cumulative Layout Shift(CLS)指标。
<img src="image.jpg" width="800" height="600" alt="image">5. 虚拟列表:
长列表用虚拟滚动(Virtual Scroll)只渲染可视区域的DOM节点减少DOM数量提升渲染性能特别是几千条以上的列表用react-windowreact-virtualizedvue-virtual-scroller等库实现。
五、运行时优化
运行时优化是让页面在运行过程中更流畅响应更快。
1. JS执行优化:
- 避免长时间任务:JS是单线程的长时间的JS任务(超过50ms)会阻塞主线程导致页面卡顿用户交互无响应把大的任务拆分成小的任务用setTimeoutrequestIdleCallback等分片执行。
- 防抖和节流:scrollresizeinputmousemove等高频事件用防抖(debounce)和,节流(throttle)减少事件处理函数的执行次数提升性能。
- Web Worker:计算密集型的任务(大数据处理复杂计算等等)放到Web Worker里执行不阻塞主线程保持页面响应。
- 避免内存泄漏:及时清理定时器事件监听器闭包引用等等避免内存泄漏导致页面越来越卡特别是单页应用组件销毁时要清理资源。
- 合理使用框架:框架(ReactVue等等)有自己的性能优化机制,比如React的PureComponentmemouseMemouseCallbackVue的v-memocomputed等等合理使用避免不必要的重渲染。
2. 事件委托:
列表里每个元素都绑定事件会增加内存占用和初始化时间用事件委托(Event Delegation)把事件绑定到父元素利用事件冒泡处理子元素的事件只需要一个事件监听器性能更好。
3. requestIdleCallback:
用requestIdleCallback把非紧急的任务(统计上报预加载等等)放到浏览器空闲时执行不影响用户交互和页面响应。
4. 合理使用缓存:
- 内存缓存:计算结果数据等等缓存起来避免重复计算用Memoization等技术。
- HTTP缓存:静态资源设置合理的缓存策略(Cache-ControlETagLast-Modified)减少重复下载提升二次访问速度。
- Service Worker:用Service Worker做离线缓存和,资源缓存提升二次访问速度和离线体验特别是PWA应用。
- 数据缓存:接口数据缓存起来避免重复请求,比如列表数据详情数据等等用内存缓存,或者本地存储(localStorageIndexedDB)。
5. 动画优化:
- 用CSS动画不用JS动画:CSS动画浏览器有优化性能更好除非需要复杂的动画控制,否则优先用CSS动画。
- 避免,同时动画太多元素:同时动画的元素太多会导致帧率下降尽量减少,同时动画的元素数量。
- 用transform和opacity:前面说过这两个属性做动画性能好不会触发重排。
- 开启GPU加速:用transform: translateZ(0)或者will-change开启GPU加速提升动画性能,但是不要滥用,否则会占用更多内存。
六、性能监控和工具
性能优化需要工具来测量和监控推荐以下工具:
1. Chrome DevTools:
Chrome开发者工具是最常用的性能分析工具包括:
- Network面板:分析资源加载时间请求瀑布流找到加载慢的资源。
- Performance面板:记录和分析页面加载和,运行的性能找到卡顿和长时间任务。
- Lighthouse:自动化性能审计工具给出性能评分和,优化建议非常实用。
- Coverage面板:分析JS和CSS的代码覆盖率找到未使用的代码减少体积。
- Memory面板:分析内存使用情况找到内存泄漏。
2. WebPageTest:
WebPageTest是在线的网站性能测试工具能在不同的地点浏览器网络条件下测试网站性能给出详细的报告和,瀑布流适合测试真实用户环境下的性能。
3. 性能监控系统:
生产环境需要性能监控系统实时监控用户的真实性能数据(RUMReal User Monitoring)比如阿里云ARMSSentryDatadog等等能收集用户的页面加载时间错误信息等等及时发现性能问题。
4. 构建工具分析:
- webpack-bundle-analyzer:分析Webpack打包体积可视化展示每个模块的大小找到体积大的模块。
- speed-measure-webpack-plugin:分析Webpack构建速度找到构建慢的Loader和Plugin。
- Source Map Explorer:分析Source Map查看打包后的代码来源找到体积大的依赖。
七、性能优化检查清单
最后给一个性能优化的检查清单方便大家对照检查:
网络:
- [ ] 使用CDN
- [ ] 启用HTTP/2
- [ ] 启用gzip/Brotli压缩
- [ ] 减少DNS查找
- [ ] 减少重定向
加载:
- [ ] 压缩JS/CSS/HTML
- [ ] 图片优化(格式压缩WebP响应式懒加载)
- [ ] 字体优化(子集化woff2font-display)
- [ ] 代码分割和懒加载
- [ ] 预加载关键资源
- [ ] 合理的缓存策略
渲染:
- [ ] 关键CSS内联
- [ ] CSS放头部JS放底部或defer/async
- [ ] 减少重排重绘
- [ ] 图片设置尺寸
- [ ] 长列表用虚拟滚动
运行时:
- [ ] 避免长时间任务
- [ ] 防抖和节流
- [ ] 复杂计算用Web Worker
- [ ] 避免内存泄漏
- [ ] 事件委托
- [ ] 合理使用缓存
- [ ] 动画优化
监控:
- [ ] 用Lighthouse审计
- [ ] 用Chrome DevTools分析
- [ ] 生产环境性能监控
- [ ] 构建体积分析
八、写在最后
以上就是我总结的前端性能优化最佳实践从网络加载渲染运行四个维度系统地梳理了性能优化的方法和技巧以及,工具和检查清单。
前端性能优化是一个系统工程需要从多个维度综合优化不是靠某一个技巧就能解决所有问题需要根据项目的具体情况找到瓶颈针对性优化,而且性能优化是持续的过程需要持续监控和优化。
希望我的总结能帮大家建立系统的性能优化知识体系在实际项目中做好性能优化提升用户体验。
最后用一句话结束这篇文章:"性能优化没有最好,只有更好持续测量持续优化才能给用户最好的体验。"
愿大家的网站都能又快又流畅用户体验棒棒的。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录