防抖与节流

136 阅读2分钟

防抖

多次触发,最后一次 n 秒后执行

使用场景

  • 登陆、发短信避免用户点击太快,以至于发送了多次请求
  • 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多
  • 文本编辑器实时保存
  • 表单验证:在表单输入过程中,每次用户输入都可能触发验证操作。使用防抖函数可以延迟触发验证操作,只在用户输入完毕一段时间后进行验证,避免频繁的验证操作。
  • 上拉下滑监听
  • 搜索框实时搜索:当用户在搜索框中输入内容时,通常需要实时进行搜索。使用防抖函数可以延迟搜索请求的发送,只在用户停止输入一段时间后才真正发送请求,避免频繁的请求操作。
  • 鼠标移动事件:在一些特定的交互场景中,需要根据鼠标的移动位置做出相应的交互。使用防抖函数可以延迟鼠标移动事件的触发,只在用户停止移鼠标一段时间后才执行相应的操作,避免过度频繁的操作。

实现

function debounce(fn, wait, immediate = false) {
  let timer = 0;
  let isInvoke = false;
  return function (...args) {
    if (timer) clearTimeout(timer);

    if (immediate && !isInvoke) {
      fn.apply(this, args);
      isInvoke = true;
    } else {
      timer = setTimeout(() => {
        !immediate && fn.apply(this, args);
        isInvoke = false;
      }, wait);
    }
  };
}

节流

多次触发,n 秒内执行一次

使用场景

  • 监听滚动事件
  • DOM 拖拽功能
  • 射击游戏
  • 计算鼠标移动距离

实现

function throttle(func, wait, options = {}) {
  let timeout = 0;
  let oldTime = 0;
  const { leading = false, trailing = true } = options;
  return function (...args) {
    let newTime = new Date().valueOf();

    if (newTime - oldTime > wait && leading !== false) {
      func.apply(this, arguments);
      oldTime = newTime;
      if (timeout) {
        //关键代码块
        clearTimeout(timeout);
        timeout = 0;
      }
    }
    if (!timeout && trailing !== false) {
      timeout = setTimeout(() => {
        oldTime = new Date().valueOf(); //关键代码
        timeout = 0;
        func.apply(this, args);
      }, wait);
    }
  };
}

参考

小马哥