JavaScript性能优化需针对性使用技术:批量DOM操作用DocumentFragment或HTML字符串;节流防抖按场景选,注意leading/trailing配置;闭包泄漏用WeakMap或显式移除监听器;requestIdleCallback用于非关键异步任务,不可替代rAF或同步逻辑。
JavaScript性能优化不是加个use strict就变快,也不是盲目压缩代码——它是在真实卡顿、内存上涨、滚动掉帧发生时,你手上有几把能立刻用的“扳手”。
每次appendChild、innerHTML赋值或读取offsetTop,都可能强制浏览器同步计算布局(Reflow),高频操作会让主线程直接卡死。
document.createDocumentFragment()在内存中攒好所有节点,最后一次性挂载list.innerHTML = htmlString),比逐个createElement快,但要注意XSS风险document.query
Selector——查一次缓存起来,别每次重走DOM树el.offsetHeight,再设el.style.width,浏览器会立刻回流——读完再写,批量读、批量写不是所有高频事件都适合debounce;选错会导致交互失灵或响应延迟。
throttle:适合持续触发的场景,比如scroll、mousemove——保证每200ms最多执行一次,不丢事件debounce:适合“等用户停下来再干活”的场景,比如搜索框输入、resize——最后一次输入后等300ms再发请求_.throttle默认不触发首尾调用,得手动加{ leading: true, trailing: true },否则滚动一开始和结束都收不到回调requestIdleCallback,但throttle/debounce纯JS实现无依赖,可直接落地闭包本身不拖慢执行,但它容易“悄悄留住不该留的东西”,比如一个10MB的数组或整个document.body。
el.addEventListener('click', () => doSomething(bigData))——箭头函数捕获了bigData,而el长期存在,bigData就永远无法GCWeakMap存私有数据,键是DOM元素,值是关联状态,元素被移除后自动释放removeEventListener配对清理,别用匿名函数Detached或大对象引用链它不是“另一个定时器”,而是浏览器明确告诉你:“现在主线程空闲,你可以干点不着急的事”。
requestAnimationFrame)、必须立即执行的校验逻辑setTimeout(fn, 0)或轻量polyfill;但别在核心路径里用它做兜底,只用于锦上添花真正卡顿的根源往往藏在“看起来没问题”的地方:比如一个没清理的resize监听器,或缓存了整个dataset对象的闭包。优化不是堆技巧,而是养成用Performance面板录一下、用Memory截个快照的习惯——问题在哪,扳手就往哪拧。