JavaScript性能优化需聚焦执行效率、内存占用和渲染响应三方面,核心是避免DOM频繁操作、合理使用节流防抖、减少闭包内存泄漏、用requestIdleCallback处理低优先级任务,并通过Performance面板定位真实瓶颈。
JavaScript 性能优化不是“加个 use strict 就变快”,而是围绕执行效率、内存占用和渲染响应这三块做针对性干预。多数卡顿问题,80% 出在 DOM 操作、事件绑定不当或闭包意外持有了大对象。
每次读写 offsetTop、clientWidth 或修改 style 属性,都可能强制浏览器同步计算布局。连续操作会放大开销。
const rect = el.getBoundingClientRect(),再取 rect.width、rect.height
className 或 cssText 一次性应用样式,而不是逐个设 el.style.color = 'red'; el.style.fontSize = '14px'
transform 和 opacity 做动画——它们走合成层(Compositor),不触发布局计算不是所有高频事件都该用防抖;滚动、鼠标移动这类持续触发的,节流更合理;而搜索框输入、窗口大小调整,才适合防抖。
throttle:保证每 n 毫秒最多执行一次,适合监听 scroll 或 mousemove
debounce:最后一次触发后等待 n 毫秒再执行,适合 input 输入校验、resize
_.throttle 而不设 {leading: true, trailing: true}——默认可能丢掉首尾调用function throttle(fn, delay) {
let last = 0;
return function(...args) {
const now = Date.now();
if (now - last > delay) {
fn.apply(this, args);
last = now;
}
};
}闭包本身不慢,但若内部函数长期存活(比如绑在全局事件上),又捕获了本不该保留的大数组或 DOM 节点,就会阻止垃圾回收,导致内存泄漏。
console.memory 和 Chrome DevTools 的 Memory 面板,用 “Heap Snapshot” 对比前后差异el.addEventListener('click', () => doSomething(data)) → 改用预绑定或外部命名函数WeakMap 存储私有数据,它不会阻止键对象被回收requestIdleCallback 处理低优先级任务不是所有逻辑都要立刻执行。像日志上报、非关键状态更新、预加载,可以塞进空闲时段,避免抢占主线程。
setTimeout(fn, 0) 或用 requestIdleCallback polyfillif ('requestIdleCallback' in window) {
requestIdleCallback(() => {
console.log('空闲时执行');
}, { timeout: 2000 });
} else {
setTimeout(() => console.log('降级执行'), 0);
}真正影响性能的,往往不是某一行代码多慢,而是多个小决策叠加出的延迟链路。比如一个 for 循环本身很快,但如果它在每次迭代中都查一次 document.getElementById,就变成了 O(n²) 级别的开销。动手前,先用 Performance 面板录一段真实操作,
看瓶颈到底落在哪。