12.函数防抖,函数节流
一、函数防抖
1、什么是函数防抖
- 事件触发后,等待一段时间(延迟)。若在等待期间再次触发事件,则重新计时。 
- 只有最后一次触发生效,之前的触发均被取消。 
2、函数防抖代码实现
- immediate = false,则每次在 delay 后执行一次函数,首次不会执行
- immediate = true,则首次触发立即执行,之后在 delay 后执行一次函数
function debounce(func, delay, immediate = false) {
  // 闭包保存的定时器标识
  let timer;
  // 返回防抖处理后的函数(接收任意参数)
  return function (...args) {
    const that = this;
    const callNow = immediate && !timer; // 判断是否满足"立即执行"条件
    clearTimeout(timer); //  每次触发都先清除之前的定时器
    timer = setTimeout(() => {
      timer = null;
      // 若非立即执行模式,则在延迟后调用目标函数
      if (!immediate) {
        // 确保正确的 this 和参数传递
        func.apply(that, args);
      }
    }, delay);
    // 如果满足立即执行条件,则立即调用目标函数
    if (callNow) func.apply(that, args);
  };
}
二、函数节流
1、什么是函数节流
- 无论事件触发多频繁,固定时间间隔内只执行一次函数。 
- 稀释函数的执行频率,保证周期性调用。 
2、函数节流代码实现
// 时间戳版本(立即执行首次)
function throttle(func, delay) {
  let lastTime = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= delay) {
      func.apply(this, args);
      lastTime = now;
    }
  };
}
// 定时器版本(延迟执行首次)
function throttle(func, delay) {
  let timer = null;
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, delay);
    }
  };
}
三、应用场景
| 场景 | 技术方案 | 原因 | 
|---|---|---|
| 列表页滚动加载更多 | 节流 | 需要周期性触发(如每 500ms),保证加载节奏,避免遗漏中间滚动位置。 | 
| 搜索框输入联想 | 防抖 | 用户停止输入后才请求结果,避免无效中间请求(如输入 “abc”时只查“abc”)。 | 
| 按钮防重复提交 | 防抖(立即执行) 或 节流 | 根据需求选择:立即执行首次点击,屏蔽后续点击(防抖 + immediate=true)。固定间隔内只允许提交一次(节流)。 | 
| 窗口大小调整布局计算 | 防抖 | 调整结束后计算一次布局,避免频繁重绘。 | 
| 游戏角色移动控制 | 节流 | 限制高频按键响应频率,保证操作流畅性(如每 100ms响应一次方向键)。 | 
