javascript中的防抖与节流

在javascript中,防抖与节流的实

阅读量:1001

点赞量:19

评论量:0
Skill
标签摘要
在javascript中,防抖与节流的实现和应用。
正文

节流与防抖用于函数被多次触发时,不同的处理方式

异同

相同点

都是为了处理函数触发的频率。

不同点

防抖:在函数触发n秒后再执行回调,在时间阈值内再次调用函数,将清除掉上次执行的回调,重新计算时间。

节流:函数触发的n秒内,再次调用函数,将不会处理,只有过了时间阈值才能再次触发。

既:在小于时间阈值内多次调用函数,防抖只会执行一次,而节流可以执行多次。

简单实现

/**
 * 防抖
 * @param fn 回调函数
 * @param delay 时间阈值
 * @returns 函数
 */
export function debounce(fn: (...args: unknown[]) => void, delay: number) {
  let timer: any = null
  return (...args: unknown[]) => {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn(...args)
    }, delay)
  }
}

/**
 * 节流
 * @param fn 回调函数
 * @param delay 时间
 * @returns 函数
 */
export function throttle(fn: (...args: unknown[]) => void, delay: number) {
  let valid = true
  return (...args: unknown[]) => {
    if (!valid) {
      return
    }
    valid = false
    setTimeout(() => {
      fn(...args)
      valid = true
    }, delay)
  }
}

上面的方法简单的实现了防抖与节流,但实际应用中,有时需要回调函数立即执行,或者取消已经执行但还未触发回调的函数,那就需要进一步封装了。

进一步实现

/**
 * 防抖函数
 * @return 防抖函数
 * @param func 要执行的函数
 * @param wait 间隔时间(毫秒)
 * @param immediate 是否立即执行
 */
export function debounce(
  func: (...args: unknown[]) => void,
  wait: number,
  immediate?: boolean,
) {
  let timer;
  return (...args: unknown[]) => {
    if (timer) {
      clearTimeout(timer);
    }
    if (immediate) {
      const isCan = !timer;
      timer = setTimeout(() => {
        timer = null;
      }, wait);
      if (isCan) {
        func(...args);
      }
    } else {
      timer = setTimeout(() => {
        func(...args);
      }, wait);
    }
    return () => {
      if (timer) {
        clearTimeout(timer);
      }
    };
  };
}

/**
 * 节流函数
 * @return 节流函数
 * @param func 要执行的函数
 * @param wait 间隔时间(毫秒)
 * @param immediate 是否立即执行
 */
export function throttle(
  func: (...args: unknown[]) => void,
  wait: number,
  immediate?: boolean,
) {
  let previous;
  return (...args: unknown[]) => {
    if (immediate) {
      const now = Date.now();
      if (now - previous > wait) {
        func(...args);
        previous = now;
      }
    } else {
      if (!previous) {
        previous = setTimeout(() => {
          previous = null;
          func(...args);
        }, wait);
      }
    }
    return () => {
      if (previous) {
        clearTimeout(previous);
      }
    };
  };
}

使用上面的方法,创建的防抖和节流函数会返回取消方法,但仅能取消还未执行的回调函数,对于立即执行的无效。

下面是测试的例子:

27e82ac922d8234aa63dba03a2e8993.jpg

e4e522dbc4d6803bd56638fb46d1abb.jpg

d18c35582043f99ba5f506b395abf72.jpg

其他的就不测试了。

用途

1、富文本编辑实时保存问题,可以使用节流函数。

2、窗口大小改变或者鼠标滚动,根据需求使用。

3、浏览器无法监听页面停止滚动,可以再页面滚动时添加防抖函数,来处理停止滚动的逻辑。比如本页面,在页面滚动时会让小猫动画运行,页面停止滚动则暂停动画,暂停动画就是使用防抖函数在页面滚动时添加的。

4、其他,还是看需求。

后语

上面封装的函数都是使用ts写的,用的es6的箭头函数,若需要使用es5语法,为防止this指向改变,可以使用arguments和apply来实现this指向和参数传递。

...

return function () {

  const content = this;

  const args = arguments;

  ...

    fun.apply(content, args)

  ...

}

...

关于改变this指向

关于闭包

发布于: 9/4/2022, 5:23:03 PM
最后更新: 12/3/2024, 3:32:43 AM