前端性能优化全家桶:从重绘重排到面试连招,一篇搞懂

性能优化这件事,说简单也简单,说复杂也复杂。核心思想一句话:让浏览器少干活,还得干得快

今天这篇文章,我们从最基础的 重绘、重排 开始,聊到 资源加载、JS 执行、框架优化、缓存、网络、首屏渲染 ,再配上 性能指标、工具和面试连招,让你从理论到实战全覆盖。


一、重绘 & 重排:浏览器最怕的"体力活"

浏览器的渲染流程大概是这样的:

布局(Layout) → 绘制(Paint) → 合成(Composite)

两个关键概念:

  • 重绘(Repaint) 样式改变但位置没动,比如颜色、背景。
  • 重排(Reflow) 尺寸或位置发生变化,需要重新计算布局。

口诀:

重排一定会触发重绘,重绘不一定触发重排。重排开销更大!


1. 批量修改 DOM

❌ 不推荐:

js 复制代码
const el = document.getElementById('myEl');
el.style.width = '100px';
el.style.height = '100px';
el.style.margin = '10px';

✅ 推荐:

js 复制代码
el.style.cssText = 'width: 100px; height: 100px; margin: 10px;';
// 或者直接通过类名
el.className = 'my-class';

2. 使用文档碎片

批量添加节点用 document.createDocumentFragment,只触发一次渲染:

js 复制代码
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
  const el = document.createElement('div');
  fragment.appendChild(el);
}
document.body.appendChild(fragment);

3. 脱离文档流后再修改

js 复制代码
const el = document.getElementById('myEl');
el.style.display = 'none';
// 批量修改
el.style.display = 'block';

4. 缓存布局信息

避免重复触发重排:

js 复制代码
// ❌ 每次循环都会触发重排
for (let i = 0; i < 100; i++) {
  el.style.top = el.offsetTop + 1 + 'px';
}

// ✅ 缓存 offsetTop
let top = el.offsetTop;
for (let i = 0; i < 100; i++) {
  el.style.top = ++top + 'px';
}

5. 用 transform 代替 top/left

js 复制代码
// ❌ 会触发布局
el.style.left = '100px';

// ✅ 只触发重绘
el.style.transform = 'translateX(100px)';

二、资源加载优化

少加载、不阻塞、格式更高效:

  • 图片懒加载

    html 复制代码
    <img loading="lazy" src="xxx.jpg">
  • 路由懒加载 / 代码分割

    js 复制代码
    const Home = React.lazy(() => import('./Home'));
  • 资源预加载

    html 复制代码
    <link rel="dns-prefetch" href="//cdn.example.com">
    <link rel="preload" href="/main.css">
    <link rel="prefetch" href="/next-page.js">
  • WebP 格式图片:小一半体积,质量无损。

  • 字体图标库:减少几十个 HTTP 请求。


三、JS 执行优化

  • 防抖、节流:减少高频事件触发次数。
  • Web Worker:让复杂计算不堵主线程。
  • requestAnimationFrame:动画更丝滑。
  • requestIdleCallback:浏览器闲时干活,React Fiber 就用它实现调度。

四、框架层优化

React/Vue 项目常见套路:

  • memo / useMemo / useCallback 避免不必要渲染。
  • 按需加载组件库,如 shadcn-uiantd
  • 列表渲染合理使用 key,减少 Diff 计算。

五、缓存策略

缓存是性能优化的"性价比王者"。

  • 强缓存(不发请求)

    http 复制代码
    Cache-Control: max-age=3600
    Expires: Wed, 21 Oct 2025 07:28:00 GMT
  • 协商缓存(发请求,返回 304)

    http 复制代码
    Last-Modified / If-Modified-Since
    ETag / If-None-Match
  • 本地缓存

    • localStorage
    • sessionStorage
    • cookie

六、网络优化

  • CDN 加速:资源离用户更近。

  • Gzip 压缩:资源小,加载快。

  • HTTP/2 多路复用:一个连接跑多请求。

  • DNS 预解析

    html 复制代码
    <link rel="dns-prefetch" href="//cdn.example.com">

七、首屏优化

  • SSR(服务端渲染):先把 HTML 渲染好再发给浏览器。
  • 骨架屏:用户看起来更快。
  • HTTP/2 Server Push:首屏资源提前推送。

八、性能测试工具

  • Chrome Performance 定位瓶颈,分析渲染和脚本耗时。
  • Lighthouse 性能、无障碍、SEO 等多维打分。

常见优化建议:

  • 首屏 JS、CSS 体积减小(代码分割)
  • 图片用 WebP
  • 动画尽量用 transform
  • 按需加载组件库

九、核心性能指标

  • FCP(First Contentful Paint) 首次内容绘制时间。
  • LCP(Largest Contentful Paint) 最大内容绘制时间,影响用户"页面加载完毕"的感知。

十、面试高频问题

性能优化在面试里是高频考点,以下是一些常见题型和答题套路。


Q1:重绘和重排的区别?怎么优化?

  • 区别

    • 重绘:样式变化但位置没变。
    • 重排:尺寸或位置改变,需要重新布局。
  • 优化

    • 批量修改 DOM
    • 使用文档碎片
    • 脱离文档流操作
    • 缓存布局信息
    • transform 代替 top/left

Q2:首屏加载优化有哪些方案?

  • 代码分割、懒加载、按需加载
  • Gzip、CDN 加速
  • SSR、骨架屏
  • 强缓存 + 协商缓存组合拳
  • HTTP/2 多路复用

Q3:长列表如何优化?

  • 合理使用 key
  • 虚拟列表技术(react-window
  • 配合 memouseCallback 避免重复渲染

Q4:如何监控和分析性能?

  • 开发阶段:Chrome Performance、Lighthouse
  • 线上阶段:埋点上报 FCP、LCP、CLS;Sentry/ARMS 做监控

Q5:代码优化可以做哪些?

  • 防抖、节流减少高频调用
  • Web Worker 分担计算压力
  • 动画用 requestAnimationFrame
  • 减少无意义的深拷贝或频繁 state 更新

Q6:首页很慢,怎么排查?

  1. 资源问题:JS/CSS 是否太大?图片是否优化?
  2. 网络问题:DNS 解析、CDN 节点延迟。
  3. 渲染问题:同步 JS 阻塞渲染。
  4. 缓存问题:是否未命中缓存。

加分技巧:

答题时用"场景 + 措施 + 效果"的模式:

"项目首页加载慢,排查发现 JS 包 3M,通过 Webpack 分包和懒加载降到 500KB,首屏渲染从 3 秒降到 1.5 秒。"

这样的回答更有说服力!


结语

性能优化不是某个大招,而是一系列"小动作"的积累:

  • 写代码时减少无意义的 DOM 操作
  • 打包部署时合理做缓存和分割
  • 上线后持续监控指标,优化体验

做多了,你会发现,项目从"能跑"到"飞起",就差这些细节。

相关推荐
excel5 小时前
ES6 中函数的双重调用方式:fn() 与 fn\...``
前端
可乐爱宅着5 小时前
全栈框架next.js入手指南
前端·next.js
bobz9655 小时前
进程和线程结构体的统一和差异
面试
你的人类朋友7 小时前
什么是API签名?
前端·后端·安全
会豪9 小时前
Electron-Vite (一)快速构建桌面应用
前端
中微子9 小时前
React 执行阶段与渲染机制详解(基于 React 18+ 官方文档)
前端
唐某人丶9 小时前
教你如何用 JS 实现 Agent 系统(2)—— 开发 ReAct 版本的“深度搜索”
前端·人工智能·aigc
中微子9 小时前
深入剖析 useState产生的 setState的完整执行流程
前端
遂心_9 小时前
JavaScript 函数参数传递机制:一道经典面试题解析
前端·javascript
小徐_23339 小时前
uni-app vue3 也能使用 Echarts?Wot Starter 是这样做的!
前端·uni-app·echarts