核心是减少主线程阻塞以保障响应性,通过任务拆分、Web Workers、微宏任务合理调度、节流防抖及DOM优化等手段实现。

核心是让主线程不被长时间占用,确保用户操作能被及时响应。关键不在“加功能”,而在“减阻塞”和“控节奏”。
拆分长任务,避免主线程卡死
超过50ms的同步执行会被浏览器标记为“长任务”,直接导致页面卡顿、输入延迟。不能靠等它跑完,得主动切片。
- 用
setTimeout或queueMicrotask把大循环/大数据处理拆成小块,每执行一段就让出控制权 - 对列表渲染、数据转换等场景,优先用
requestIdleCallback——只在浏览器空闲时执行,不影响用户交互 - 真正耗时的操作(如图像处理、复杂计算)移出主线程,交给 Web Workers 处理
善用微任务与宏任务的执行优先级
Promise 回调、queueMicrotask 属于微任务,会在当前宏任务结束后立即、连续执行;而 setTimeout 是宏任务,要等到下一轮事件循环。合理搭配能提升响应节奏。
- 需要“尽快但不打断当前流程”的逻辑(如状态更新后的轻量校验),用
Promise.resolve().then(...)或queueMicrotask - 需要“延后且不抢占”的逻辑(如日志上报、非关键UI更新),用
setTimeout(..., 0)或postMessage - 避免在微任务中递归触发新微任务,否则会饿死宏任务,导致 UI 渲染停滞
节流高频事件,减少队列堆积
滚动、鼠标移动、窗口缩放等事件可能每秒触发数十次。不加控制就会让任务队列迅速积压,拖慢整体响应。
立即学习“Java免费学习笔记(深入)”;
- 对必须响应的场景(如滚动定位),用节流(throttle)——固定间隔只执行一次
- 对只需最终结果的场景(如搜索框输入),用防抖(debounce)——停止触发后才执行
- 现代方案可结合
requestAnimationFrame:把 DOM 更新统一安排在下一帧开始前,避免重复重排重绘
减少同步阻塞,释放事件循环资源
事件循环本身无法优化,但你能决定往它里面塞什么。很多卡顿源于本不该出现在主线程的代码。
- 避免在事件处理器里做大量计算、深克隆或正则匹配;提前预处理或缓存结果
- 批量 DOM 操作合并进行,用
DocumentFragment或innerHTML替代频繁的单个appendChild - 及时清理不再需要的定时器、事件监听器和闭包引用,防止内存泄漏拖慢 GC 周期


















