全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-16 10 分钟 ✍️ juanwangdev

JavaScript 性能优化(内存管理、防抖节流)

性能优化需要理解内存管理机制,并合理使用防抖节流控制执行频率。

内存管理基础

内存生命周期

  1. 分配:声明变量、对象时分配内存
  2. 使用:读写内存中的值
  3. 释放:不再需要时释放内存
JavaScript
// 分配
let obj = { name: 'Alice' };

// 使用
console.log(obj.name);

// 释放(解除引用)
obj = null;

垃圾回收机制

JavaScript 使用标记-清除算法:

JavaScript
// 可达对象不会被回收
let user = { name: 'Alice' };
user = null;  // { name: 'Alice' } 变为不可达,将被回收

// 循环引用(现代 GC 可处理)
function createCycle() {
  let obj1 = {};
  let obj2 = {};
  obj1.ref = obj2;
  obj2.ref = obj1;
  return 'done';
}
createCycle();  // obj1、obj2 离开作用域后可被回收

常见内存泄漏

1. 意外的全局变量

JavaScript
function leak() {
  bar = 'global';  // 意外创建全局变量
}

// 解决:使用严格模式
'use strict';
function noLeak() {
  const bar = 'local';
}

2. 未清理的定时器

JavaScript
// 泄漏
function startTimer() {
  const data = new Array(1000000);
  setInterval(() => {
    console.log(data.length);  // data 一直被引用
  }, 1000);
}

// 解决
let timerId;
function startTimer() {
  const data = new Array(1000000);
  timerId = setInterval(() => {
    console.log(data.length);
  }, 1000);
}
function stopTimer() {
  clearInterval(timerId);
}

3. 未移除的事件监听

JavaScript
// 泄漏
class Component {
  constructor() {
    this.data = new Array(1000000);
    window.addEventListener('resize', this.handleResize);
  }
  handleResize = () => {
    console.log(this.data.length);
  }
}

// 解决
class Component {
  constructor() {
    this.data = new Array(1000000);
    window.addEventListener('resize', this.handleResize);
  }
  handleResize = () => {
    console.log(this.data.length);
  }
  destroy() {
    window.removeEventListener('resize', this.handleResize);
  }
}

4. 闭包引用

JavaScript
// 泄漏:闭包持有大对象
function createHandler() {
  const largeData = new Array(1000000);
  return () => console.log(largeData.length);
}

// 解决:只保留必要数据
function createHandler() {
  const largeData = new Array(1000000);
  const length = largeData.length;
  return () => console.log(length);
}

防抖(Debounce)

延迟执行,在等待期间再次触发则重新计时:

JavaScript
function debounce(fn, delay) {
  let timerId = null;
  return function(...args) {
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 使用
const handleInput = debounce((value) => {
  console.log('搜索:', value);
}, 300);

input.addEventListener('input', (e) => {
  handleInput(e.target.value);
});

立即执行版防抖

JavaScript
function debounceImmediate(fn, delay) {
  let timerId = null;
  return function(...args) {
    if (!timerId) {
      fn.apply(this, args);  // 首次立即执行
    }
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      timerId = null;
    }, delay);
  };
}

节流(Throttle)

固定间隔执行,忽略间隔内的重复触发:

JavaScript
function throttle(fn, interval) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      lastTime = now;
      fn.apply(this, args);
    }
  };
}

// 使用
const handleScroll = throttle(() => {
  console.log('滚动位置:', window.scrollY);
}, 200);

window.addEventListener('scroll', handleScroll);

定时器版节流

JavaScript
function throttleTimer(fn, interval) {
  let timerId = null;
  return function(...args) {
    if (!timerId) {
      timerId = setTimeout(() => {
        fn.apply(this, args);
        timerId = null;
      }, interval);
    }
  };
}

防抖 vs 节流

特性防抖节流
执行时机停止触发后执行固定间隔执行
适用场景搜索输入、窗口resize滚动、拖拽
触发频率最后一次固定间隔

应用场景

JavaScript
// 搜索框输入
searchInput.addEventListener('input', debounce(search, 300));

// 窗口大小调整
window.addEventListener('resize', debounce(updateLayout, 200));

// 页面滚动
window.addEventListener('scroll', throttle(updatePosition, 100));

// 鼠标移动
document.addEventListener('mousemove', throttle(logPosition, 50));

要点总结

  • JavaScript 自动垃圾回收,但仍需注意内存泄漏
  • 常见泄漏:全局变量、定时器、事件监听、闭包
  • 防抖:延迟执行,频繁触发时重置计时
  • 节流:固定间隔执行,稀释触发频率
  • 根据场景选择:搜索用防抖,滚动拖拽用节流

📝 发现内容有误?点击此处直接编辑

← 上一篇 JavaScript 原型链
下一篇 → JavaScript 模块化(ES Modules)
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库