性能优化
一、加载性能优化
代码分割与懒加载
- 原理:利用
Webpack动态导入 (import()) 或框架路由懒加载(如 React.lazy、Vue 异步组件)。 【把代码分离到不同的bundle中,然后按需加载或并行加载文件 用于获取更小的bundle,控制资源加载优先级 ● 入口起点:使用 entry 配置手动地分离代码。 ○ 如果入口 chunk 之间包含一些重复的模块,那些重复模块都会被引入到各个 bundle 中。 ○ 这种方法不够灵活,并且不能动态地将核心应用程序逻辑中的代码拆分出来。 ● 防止重复:使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离 chunk。 ● 动态导入:通过模块的内联函数调用来分离代码。动态导入一个模块时,模块会分离到一个单独的bundle 】 - 场景:例如首页仅加载首屏模块,其他详情页通过路由懒加载拆分,降低首屏体积。
- 效果:首屏加载时间从 3s → 1.5s,FCP(首次内容渲染)提升 40%。
- 原理:利用
资源压缩与 CDN 加速
实践:使用
Webpack的 Terser 压缩 JS,imagemin压缩图片,CSS 提取为独立文件并压缩 使用到webpack的打包优化,参考webpack优化的文章 TODO 减少请求数、减小请求资源体积、提升网络传输速率 压缩html,js,css 服务器上开启Gzip传输压缩(比如 vue打包后支持压缩体积,nginx可以开启gzip传输),它能将我们的文本类文件体积压缩至原先的四分之一 有时候ui提供的字体资源文件过大,高达几M,这时可以结合字体属性,使用字体分包,将字体文件分成按需加载的小份包,技术内幕【https://chinese-font.netlify.app/post/font_split_turbo/】nginx开启gzip,来压缩文本资源(HTML/CSS/JS),可以减少传输体积
场景:官网项目静态资源非常多包括字体文件,图片等,静态资源上传至 CDN(如阿里云 OSS),通过
dns-prefetch预解析域名。指标:资源体积减少 60%,CDN 加速后全球访问延迟降低 30%。
HTTP/2 与预加载
- 策略:开启 HTTP/2 多路复用(和HTTP/1的区别和现象,nginx开启多路复用),使用
preload加载关键字体/CSS,preconnect预连接第三方域名。 详细可以查看nginx优化配置 ● preload 是告诉浏览器页面必定需要的资源,浏览器一定会加载这些资源; ● prefetch 是告诉浏览器页面可能需要的资源,浏览器不一定会加载这些资源。预测会加载指定资源,如在我们的场景中,我们在页面加载后会初始化首屏组件,当用户滚动页面时,会拉取第二屏的组件,若能预测用户行为,则可以 prefetch 下一屏的组件。 - 案例:新闻网站预加载首屏文章字体,避免 FOIT(字体未加载时的空白)。vue框架中是怎么做预加载
preload的
- 策略:开启 HTTP/2 多路复用(和HTTP/1的区别和现象,nginx开启多路复用),使用
index.html中可以指定独立脚本文件
路由中可以设置路由懒加载
webpack配置哪些资源可以预加载或者懒加载(默认的配置可能会造成一些资源浪费,比如默认开启prefetch,而prefetch会加载将来可能不会使用到的资源,造成开屏很慢,如果你的应用很大且有很多 async chunk,而用户主要使用的是对带宽较敏感的移动端,那么你可能需要关掉 prefetch 链接并手动选择要提前获取的代码区块。) vue打包后js脚本默认为defer,原因如下:
优化加载性能:defer 可以让 JavaScript 文件异步加载,避免脚本阻塞页面的渲染。Vue 使用 Webpack 或 Vite 等构建工具打包时,会自动在打包后的 index.html 中为 JavaScript 文件添加 defer 属性,以提高页面加载性能。
避免阻塞渲染:如果没有 defer,浏览器会阻塞渲染,直到所有的脚本都下载并执行完毕,这会导致页面的首次渲染时间变长。使用 defer 可以确保页面渲染不会因为 JavaScript 文件的加载而延迟。
提高用户体验:通过延迟 JavaScript 的执行,Vue 可以更快地呈现页面的内容,用户可以更早看到页面的结构和样式,尽管某些动态行为(如交互)会稍后加载。
二、渲染性能优化
减少重排与重绘
- 技巧:使用
transform替代top/left实现动画,通过will-change提示浏览器优化。 技巧补充(在css方面的优化):- 图片在渲染前指定大小:因为img元素是内联元素,所以在加载图片后会改变宽高,严重的情况会导致整个页面重排,所以最好在渲染前就指定其大小
- 多使用伪元素
- 字体图标? 考点:重排和重绘的区别 重绘和重排 重排是由CPU处理的,而重绘是由GPU处理的,CPU的处理效率远不及GPU,并且重排一定会引发重绘,而重绘不一定会引发重排。所以在性能优化工作中,我们更应当着重减少重排的发生。
- 场景:轮播图动画使用
transform: translateX(),避免频繁触发重排。 - 工具:Chrome DevTools 的 Performance 面板分析渲染耗时。
- 技巧:使用
虚拟列表 (Virtual List)
- 原理:仅渲染可视区域内的列表项(如
react-window、vue-virtual-scroller)。 - 场景:后台管理系统渲染 10,000 条数据时,DOM 节点从 10k → 20 个,内存占用减少 80%,遇到系统崩溃的情况,交易管理系统每个层级的数据级多达到千级甚至万级,比如账户级
- 原理:仅渲染可视区域内的列表项(如
防抖与节流
- 应用:搜索框输入使用防抖(300ms 延迟请求),滚动事件监听使用节流。
- 代码:javascript
const debounceSearch = _.debounce(() => fetchData(keyword), 300); input.addEventListener('input', debounceSearch);
三、缓存策略
强缓存与协商缓存
- 配置:Nginx 设置
Cache-Control: max-age=31536000(JS/CSS 强缓存),Etag验证文件变更。 - 效果:重复访问页面时,90% 的静态资源命中缓存,减少服务器压力。
- 配置:Nginx 设置
Service Worker 离线缓存
- 实现:使用
Workbox预缓存关键资源,实现离线访问(PWA 应用)。 - 场景:资讯类 App 离线缓存最新 10 篇文章,提升弱网用户体验。
- 实现:使用
四、框架级优化
React 优化
- Memoization:
React.memo缓存组件,useMemo/useCallback避免重复计算。 - 场景:表格组件在 props 未变化时跳过渲染,性能提升 50%。
- Memoization:
Vue 优化
- v-once:静态内容标记
v-once,避免重复编译。 - Object.freeze:冻结大数据列表,避免 Vue 响应式劫持。
- v-once:静态内容标记
五、监控与分析
- 性能指标
- Core Web Vitals:优化 LCP(最大内容渲染时间)、CLS(累积布局偏移)、FID(首次输入延迟)。
- 工具:Lighthouse 评分从 60 → 85,使用
PerformanceObserver监控真实用户数据。
关于性能指标的补充:可参考https://web.dev/articles/vitals?hl=zh-cn#其他-web-指标,有非常详细的研究,时效性也很强 一般关注这三个特性:加载速度、互动性和视觉稳定性 Largest Contentful Paint (LCP):衡量加载性能。为了提供良好的用户体验,应在网页首次开始加载的 2.5 秒内完成 LCP。 Interaction to Next Paint (INP):衡量互动性。为了提供良好的用户体验,网页的 INP 应不超过 200 毫秒。 Cumulative Layout Shift (CLS):衡量视觉稳定性。为了提供良好的用户体验,网页的 CLS 应保持在 0.1 或更低。
FP(First Paint)是 Web 性能监测指标之一,指的是页面的首次渲染时间,即浏览器首次将任何内容渲染到屏幕上的时间点。FP 是用户感知页面加载速度的第一个关键指标,通常用来评估页面的加载速度和用户体验。 FCP:首次内容绘制,浏览器首次绘制DOM的时间,这是用户第一次看到的内容。最佳用户体验的FCP建议在2秒以内,如果超过4秒则表示页面首次内容绘制很慢。(哪些调整会影响该指标) 案例分析:https://juejin.cn/post/7208451786964598841
- 代码拆分分析
- 工具:
Webpack Bundle Analyzer分析产物,合并重复依赖(如 lodash 按需引入)。
- 工具:
这里补充一个点 开发过程中的性能优化
- 构建优化,omp模块化构建优化的例子
- 框架升级
高频面试问题
Q:如何从 6s 降到 2s 的首屏加载时间?
- A:分析关键路径 → 压缩首屏资源 → 懒加载非关键组件 → CDN 加速 → 服务端渲染(SSR)。
Q:优化无限滚动列表卡顿?
- A:虚拟列表 + 骨架屏占位 + 防抖加载数据。
Q:如何减少白屏时间?
- A:SSR 服务端渲染 + 内联关键 CSS + 预加载字体。