481 字
2 分钟
09 · 运行时性能

卡顿的根源:主线程被占满#

浏览器的主线程负责 JS 执行、样式计算、布局、绘制编排。一旦一段 JS 跑了太久(>50ms),主线程被独占,用户点击/滚动无响应——这就是”长任务”。INP 指标直接反映这个体验。


用 Performance 面板定位#

录制一次交互,看火焰图:哪段脚本占了长条?是否出现”Long Task”红色标记?聚焦最贵的函数,别瞎优化。


常见运行时杀手与对策#

1. 频繁重排:循环里”读写交替”触发强制同步布局。批量读写、用 requestAnimationFrame 把视觉更新集中到下一帧。

// 节流:高频事件(scroll/resize)限制执行频率
function throttle(fn, wait) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= wait) { last = now; fn(...args); }
};
}
window.addEventListener("scroll", throttle(onScroll, 100));

2. 大列表渲染:1 万行 DOM 必卡 → 虚拟列表(见 React 性能篇)。

3. 大量 DOM 操作:用文档片段(DocumentFragment)或先 display:none 改完再显示,减少重排次数。

4. 复杂计算:移到 Web Worker(下篇),不占主线程。


rAF 与防抖节流#

  • requestAnimationFrame:把动画/视觉更新对齐浏览器刷新节奏(~16ms/帧),避免掉帧。
  • debounce:停止触发 N 毫秒后才执行(搜索输入,等用户停下来再请求)。
  • throttle:固定间隔最多执行一次(滚动处理,限频)。

小结#

  • 卡顿 = 长任务占满主线程;用 Performance 面板定位最贵函数。
  • 避免循环读写交替、大列表全量渲染、无节制的 DOM 操作。
  • 防抖/节流控频率;rAF 对齐帧;重计算进 Worker。

练习#

  1. 用 Performance 录制一个卡顿交互,找出最长的 Long Task 并定位函数。
  2. 写一个高频 input 搜索,用 debounce 避免每次按键都发请求。
  3. 把一段”循环里反复改 style 触发重排”的代码改成 rAF 批量更新。
09 · 运行时性能
http://117.72.32.87/blog/posts/browser-roadmap-09-runtime-performance/
作者
Ethan
发布于
2026-10-01
许可协议
CC BY-NC-SA 4.0