js

防抖和节流

Posted by wml on April 15, 2019

背景

防抖和节流在面试过程中应该被问的频率蛮高了,工作中也时常遇到,在浏览器中,当频繁操作某个函数,且响应速度比触发速度低时,会出现卡顿,延迟,甚至假死状态,比如根据用户输入查询接口,滚动加载等;为了提高性能,不造成资源浪费,使用防抖和节流防止函数被高频触发。

防抖debounce

事件被触发时,设置定时器,延迟n秒后执行,如果n秒内该事件被再次触发,则重新计时,将频繁的事件合并为最后一次执行。

看到的一个例子觉得很形象: 电梯5秒后关门运作,有人进来,等待5秒后关门,如果期间有人进来,则又开始重新等待5秒,直到计时超过5秒,电梯关门运作。

<input type="text" id="debounce"/>

<script>
  function ajaxApi(data) { // 模拟数据请求
    console.log(new Date + ' - ' + data);
  }

  function debounce(fn, wait, immediate) {
    let timeout;
    return function() {
      let contxt = this;
      if(timeout) clearTimeout(timeout);

      if(immediate) {
          let callNow = !timeout;
          timeout = setTimeout(() => {
              timeout = null;
          }, wait);
          callNow && fn.call(contxt, ...arguments);
      }
      else {
          timeout = setTimeout(() => {
              fn.call(contxt, ...arguments);
          }, wait);
      }
    } 
}
  // var debouceAjax = debounce(ajaxApi, 1000); //高阶函数
  // document.getElementById('debounce').addEventListener('keyup', e => {
  //   debouceAjax(e.target.value)
  // })
  var debouceAjax = debounce(e => ajaxApi(e), 1000); 
  document.getElementById('debounce').addEventListener('keyup', debouceAjax);
</script>

节流throttle

事件在被触发的n秒内,即使多次被触发也只执行一次。

<input type="text" id="throttle"/>

<script>
    function ajaxApi(data) { // 模拟数据请求
        console.log(new Date + ' - ' + data);
    }

    function throttle(fn, time) {
        let timeout = null;  // 这里可以指定为一个定时器,或者直接加一个变量标识也行,原理都是一样
        return () => {
            if(timeout) return;  //如果存在计时则等待计时结束
            timeout = setTimeout(() => {
                  fn.call(this, ...arguments);
                  clearTimeout(timeout);  // 回收定时器
                  timeout = null;
            }, time)
        }
    }

    var throttleAjax = throttle(ajaxApi, 1000);

    document.getElementById('debounce').addEventListener('keyup', e => {
        throttleAjax(e.target.value)
    })
</script>

防抖和节流很相似,区别在于,防抖n秒内事件只要再次被触发就重新计时,但是节流则是n秒内只执行一次。

使用场景上,防抖适用于输入数据请求服务端这种情况;节流更适用于页面滚动或者上拉加载更多的场景。