Skip to content

渲染卡顿怎么处理? ​

先让主线程少做布局和绘制,再减少不必要的组件更新。动画用 transform 和 opacity。长列表只渲染可见项。读布局和写样式要分开批处理,避免强制同步布局。

原理 ​

强制同步布局发生在同一段脚本里交错读取几何信息(offsetWidth、getBoundingClientRect)和修改样式。浏览器为了给你最新数值,不得不提前把布局做完。正确的顺序是:先把要读的都读完,再一起写。

能不触发布局的动画就不要改 top、width、margin。transform 和 opacity 通常留在合成阶段,由 GPU 完成。will-change 只加在确实要独立成层、且数量很少的元素上,层太多会占内存。

长列表用虚拟列表,DOM 数量跟视口走,不跟数据总量走。见 无限列表。

React 里减少渲染:

  • 状态下放到真正用它的组件,避免抬得太高。
  • 列表项用稳定 key,并用 memo 挡住父组件带来的无效更新。
  • Context 按变化频率拆分。见 状态管理。
  • 输入用 startTransition 把非紧急的列表刷新标成可打断。

content-visibility: auto 让屏幕外的大块内容跳过布局和绘制。确认可访问性和滚动条高度还能接受,再使用。

追问 ​

60fps 对应多少时间?

一帧大约 16.7ms。这是预算,不是定时器间隔。一帧里要完成脚本、样式、布局、绘制和合成。超过就会掉帧。用性能面板看长任务,不要用 setTimeout(0) 去猜。

memo 是不是加得越多越好?

比较 props 本身有成本。子树很便宜时,浅比较可能更亏。先用 Profiler 找到渲染次数多、渲染又贵的节点。

易错点 ​

  • 卡顿不一定是「Vue/React 慢」。主线程上的长任务、大图片解码、同步的 localStorage 都会卡住输入。
  • 在渲染函数里创建新对象,再交给依赖它的子组件,memo 会失效。
  • 测量时开着很多扩展,结果不能代表用户。

相关 ​