一、误区:卡顿 = 技术不行 / 框架不行
常见反应:
- “是不是 Vue 太慢?”
- “是不是该上虚拟滚动?”
- “是不是要重写一遍?”
但真实情况是:
👉 大部分卡顿,来自几个固定的低级问题
而且这些问题:
- 和框架关系不大
- 和架构关系不大
- 和“你会不会写高级代码”也关系不大
本质是:
对浏览器渲染机制不敏感
二、工程化视角:卡顿的本质是“主线程被占满”
浏览器一帧的时间是:
👉 16.6ms(60FPS)
在这 16.6ms 内,要完成:
- JS 执行
- 样式计算
- 布局(回流)
- 绘制(重绘)
只要其中任何一步超时:
👉 就会掉帧 → 卡顿
所以性能问题的核心判断是:
是谁占满了主线程?
三、最常见的 4 个卡顿来源(重点)
1️⃣ 回流 & 重绘:最隐蔽的性能杀手
很多人无意中在做这种操作:
el.style.width = '100px';
console.log(el.offsetWidth);
el.style.width = '200px';
👉 读 + 写 + 读 = 强制回流
✅ 常见踩坑
- 频繁修改 DOM 样式
- 在循环中操作 DOM
- 一边读布局,一边写布局
✅ 优化方法
① 批量修改样式
el.style.cssText = 'width:100px;height:100px;';
② 读写分离
👉 先读 → 再统一写
③ 用 transform 替代布局属性
transform: translateX(100px); ✅
left: 100px; ❌
🎯 核心结论
能不触发布局,就不要触发布局
2️⃣ 图片资源:最容易被忽略的大头
很多页面卡,不是因为 JS:
👉 是图片太大
✅ 常见问题
- 一张图 2MB+
- 用原图直接展示(未压缩)
- 没有使用合适尺寸
✅ 优化方法
① 控制图片尺寸
👉 显示 300px,就不要加载 2000px 图
② 使用现代格式
- WebP
- AVIF
③ 懒加载
<img src="xx.jpg" loading="lazy" />
🎯 核心结论
图片是“最贵资源”,但最容易优化
3️⃣ 长列表:DOM 数量爆炸
典型场景:
- 渲染 1000+ 条数据
- 表格 / 聊天记录 / 商品列表
结果:
👉 页面直接卡死 or 滚动掉帧
✅ 问题本质
不是“数据多”,而是:
DOM 节点太多
✅ 优化方法
① 虚拟列表(只渲染可视区域)
核心思想:
👉 只渲染 10 条,看起来像 1000 条
② 分批渲染
requestAnimationFrame(() => {
// 分批插入 DOM
});
③ key 稳定
避免重复销毁 / 创建节点
🎯 核心结论
不是数据压垮页面,是 DOM 压垮页面
4️⃣ 事件滥用:隐形性能消耗
典型问题:
- scroll 事件里疯狂计算
- resize 触发大量逻辑
- 每个元素都绑定事件
✅ 常见错误
window.addEventListener('scroll', () => {
// 大量计算
});
👉 每一帧都在跑
✅ 优化方法
① 节流(throttle)
const throttle = (fn, delay) => {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last > delay) {
fn(...args);
last = now;
}
};
};
② 防抖(debounce)
适合 resize / input
③ 事件委托
👉 减少监听器数量
🎯 核心结论
不是事件多,而是“高频 + 重逻辑”
四、一个简单有效的排查顺序(重点)
当你遇到卡顿,不要乱优化,按这个顺序查:
① 看 DOM 数量
👉 Elements 面板:
- 是否上千节点?
② 看图片
👉 Network 面板:
- 有没有大图?
③ 看事件
👉 有没有 scroll / resize 重逻辑?
④ 再看 JS / 框架问题
👉 最后才是代码层面优化
五、真正的分水岭:不是“优化能力”,而是“避免问题”
普通开发:
👉 卡了再优化
高手:
👉 一开始就避免:
- 不乱操作 DOM
- 不加载大图
- 不直接渲染长列表
- 不滥用事件
六、落地建议(立刻见效)
1️⃣ 给自己一个“性能红线”
- DOM < 500(普通页面)
- 单图 < 200KB
2️⃣ 所有高频事件默认加节流
👉 scroll / resize / mousemove
3️⃣ 默认考虑“是否会触发回流”
写代码时多问一句:
这行代码会不会影响布局?
七、总结一句话
大多数卡顿,不是因为你不会优化,而是因为你在“无意识制造问题”。