关键在于围绕“主线程是否被长时间占用”这一核心,用Performance定位Long Task,结合防抖/节流控事件、任务拆分降单帧耗时、Web Worker卸载CPU密集计算、内存快照查泄漏源,形成可落地的优化闭环。

学防抖节流、任务拆分、内存排查、Web Worker 和运行时性能分析,关键不是逐个背概念,而是围绕“主线程是否被长时间占用”这条主线,把每个技术对准它解决的具体问题。下面按实际开发中遇到的典型卡顿场景来组织复习路径,清晰、可操作、不堆术语。
一、先盯住主线程:用 Chrome DevTools 定位真实瓶颈
所有优化都从这里开始,跳过这步容易白忙活。
- 打开 Performance 面板 → 点 Record → 模拟用户操作(比如滚动、点击、输入)→ 停止后看 Main 轨道:找标红的 Long Tasks(>50ms),它们就是卡顿的直接证据
- 重点看 FPS 曲线:掉到 30 以下说明渲染吃力;CPU 占用持续高,说明 JS 执行太重
- 切到 Memory 面板 → 拍两个 Heap Snapshot(进入页面后、执行完某操作后)→ 对比“Constructor”列,看是否有大量未释放的 DOM 节点、闭包或事件监听器
二、高频事件卡顿?防抖和节流要分清用法
不是“哪个更好”,而是“哪个更匹配当前行为逻辑”。
- 防抖(debounce):适合“等用户停下来再干活”。比如搜索框输入、窗口 resize 后重新布局。用户每敲一个字就清掉上一次定时器,只在最后停顿 delay 毫秒后执行一次
- 节流(throttle):适合“不能漏掉关键节点”。比如滚动加载、Canvas 动画控制、鼠标拖拽位置上报。保证每 delay 毫秒最多执行一次,首次触发立即执行,末次可能补调
- 注意:别在节流/防抖函数里直接操作 DOM 或触发重排。先算好数据,再批量更新,避免布局抖动
三、长任务卡死页面?拆分+卸载双管齐下
超过 16ms 的同步计算会掉帧,超过 50ms 就让用户明显感知卡顿。
-
微任务拆分:用
Promise.resolve().then()把大循环切成小块,让出主线程给渲染。适合顺序处理、无强依赖的数据遍历 -
宏任务拆分:用
setTimeout(..., 0)或requestIdleCallback(兼容性注意),适合可中断、有优先级的任务 - 真正重的活交给 Web Worker:十万行数据筛选、Excel 解析、加密解密、图表数据预处理。主线程只负责通信和 UI 更新,Worker 处理完再 postMessage 回传结果
- Worker 通信注意:传大数据用 Transferable Objects(如 ArrayBuffer),避免拷贝;频繁通信要合并消息,减少来回次数
四、内存越用越多?从引用链入手查泄漏
不是所有内存增长都是泄漏,但持续增长且不回落,大概率是没清理干净。
- 常见泄漏源:未移除的事件监听器(尤其绑定在 document/body 上)、全局变量缓存 DOM 引用、闭包中意外保留大对象、定时器未 clearTimeout/setInterval
- 排查技巧:在 Memory 面板用 Allocation instrumentation on timeline 录制操作过程,看哪类对象持续分配却不回收;对比快照时,重点关注 Closure 和 Detached DOM tree
- 修复原则:谁注册谁注销;用弱引用(WeakMap/WeakSet)缓存关联数据;组件卸载时主动清理(React 中用 useEffect cleanup,Vue 用 beforeUnmount)



















