cjfff / issue-blog

博客已经迁移至语雀
https://www.yuque.com/ubdme4/ccc
0 stars 0 forks source link

函数节流与防抖 #10

Open cjfff opened 5 years ago

cjfff commented 5 years ago

今天来梳理一下 JavaScript 中 防抖与节流

它们 两者 的目的都是为了 限制 某些事件监听的回调过于频繁的触发而进行的优化

比如:

  • window对象的 resize, scroll 事件
  • 拖拽时的 mousemove 事件
  • 文字输入、自动完成的 keyup 事件

防抖

使用场景的话,想象一下如果你要做一个 搜索 推荐,会根据用户输入的字符向后端拉取一个推荐列表,这种场景一般都是监听 input 的 keyup 事件, 用户不停的输入则不停的请求,将会造成大量的资源浪费,这时候我们就可以进行对用户输入的回调函数进行防抖包装,比如使其 一秒间隔停顿则向服务器请求数据这样子。

代码实现

const debounce = (fn, ms = 0) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer); // 每次直接清除定时器
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, ms)
  }
}

节流

函数节流会使用在比 input keyup 更频繁触发的事件中,比如 resize touchmove mousemove, scroll。 throttle 会强制的让函数以固定速率执行,因此这个方法比较适合应用于动画相关的场景。

代码实现

const throttle = (fn, wait = 0) => {
  let timer, lastTime, callNow;

  return function(...args) {
    const context = this;
    // 第一次执行
    if (!callNow) {
      fn.apply(context, args)
      lastTime = Date.now();
      callNow = true;
    } else {
      // 否则每次都取当前时间跟最后执行时间的差 和 设定的时间间隔 作为比较
      // 大于等于时间间隔则执行
      clearTimeout(timer)
      timer = setTimeout(() => {
        if (Date.now() - lastTime >= wait) {
          fn.apply(context, args);
          lastTime = Date.now()
        }
      }, Math.max(wait - Date.now() - lastTime, 0))
    }
  }
}

如果文字体会的不是很理解,可以在(页面)[http://demo.nimius.net/debounce_throttle/]中看一下可视化的比较

参考链接: https://zhuanlan.zhihu.com/p/38313717