防抖和节流的应用

防抖(debounce)和节流(throttle)是优化高频触发事件的技术,它们可以提高性能,避免不必要的计算和函数执行。以下是一些实际场景的示例:

  1. 防抖(Debounce):
    防抖用于确保一个函数在一定时间内只触发一次。它在短时间内多次触发同一个事件时,会取消之前的触发,直到最后一次触发后的一定时间间隔内没有新的触发才执行函数。常见的应用场景包括:
  • 输入框实时搜索:当用户在输入框中输入时,可以使用防抖技术延迟执行搜索查询,减少不必要的查询和服务器压力。
  • 窗口大小调整:当用户调整浏览器窗口大小时,可以使用防抖技术避免在调整过程中频繁地重新计算布局。
  • 表单验证:当用户在表单输入时,可以使用防抖技术在用户停止输入一段时间后再执行验证,减少验证的次数。
  1. 节流(Throttle):
    节流用于确保一个函数在一定时间内最多只触发一次。它会在触发事件期间以固定的时间间隔执行函数,而不管事件触发得多频繁。常见的应用场景包括:
    滚动事件监听:例如监听页面滚动到底部加载更多数据时,可以使用节流技术减少检查滚动位置的频率,提高性能。
    鼠标移动事件:例如实现一个拖拽功能,可以使用节流技术减少鼠标移动事件的处理频率。
    动画效果:当实现一个基于时间的动画效果时,可以使用节流技术限制动画帧率,降低计算开销。
    总之,防抖和节流技术都可以在不同场景下提高应用性能。防抖适用于多次触发只需执行一次的情况,而节流适用于限制连续触发事件的执行频率。
/**
 * @description 防抖函数
 * @param {Function} fn
 * @param {number} delay
 * @param {boolean} immediate
 * @returns {Function}
 */
export function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number,
  immediate: boolean = false
): T & { cancel(): void } {
  let timerId: ReturnType<typeof setTimeout> | null = null; // 存储定时器

  // 定义一个cancel方法,用于取消防抖
  const cancel = (): void => {
    if (timerId) {
      clearTimeout(timerId);
      timerId = null;
    }
  };

  const debounced = function (
    this: ThisParameterType<T>,
    ...args: Parameters<T>
  ): void {
    const context = this;
    if (timerId) {
      cancel();
    }
    if (immediate) {
      // 如果 immediate 为 true 并且没有正在等待执行的定时器,立即执行目标函数
      if (!timerId) {
        fn.apply(context, args);
      }
      // 设置定时器,在延迟时间后将 timeoutId 设为 null
      timerId = setTimeout(() => {
        timerId = null;
      }, delay);
    } else {
      // 设置定时器,在延迟时间后执行目标函数
      timerId = setTimeout(() => {
        fn.apply(context, args);
      }, delay);
    }
  };

  // 将 cancel 方法附加到 debounced 函数上
  (debounced as any).cancel = cancel;
  return debounced as T & { cancel(): void };
}

/**
 * 节流函数
 * @param func 要进行节流的目标函数
 * @param delay 节流的时间间隔(毫秒)
 * @returns 返回一个经过节流处理的函数
 */
export function throttle<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): T {
  let lastCall: number | null = null; // 上一次调用的时间戳

  return function (
    this: ThisParameterType<T>,
    ...args: Parameters<T>
  ): ReturnType<T> | void {
    const now = Date.now(); //当前时间戳
    // 如果之前没有调用过,或者时间间隔超过了设定的值,执行目标函数
    if (!lastCall || now - lastCall >= delay) {
      lastCall = now;
      return fn.apply(this, args);
    }
  } as T;
}

作者:刘晖

原文链接:https://juejin.cn/post/7232319929437257783 作者:中亿丰数字科技集团有限公司

(0)
上一篇 2023年5月13日 上午10:00
下一篇 2023年5月13日 上午10:10

相关推荐

发表回复

登录后才能评论