# 防抖

防抖

function debounce(fn, delay) {
  let timer = null;
  return function() {
    const context = this;
    const args = arguments;

    if (timer) clearTimeout(timer);
    
    timer = setTimeout(function () {
      fn.apply(context, fn);
    }, delay)
  }
}

# 应用场景

# 节流

节流,简单来说就是在指定的时间段内,传入的回调函数只触发一次,用于控制事件发生的频率。

function throttle(fn, interval) {
  let last = 0;
  return function () {
    const now = Date.now();
    const context = this;
    const args = arguments;
    if (now - last >= interval) {
      fn.apply(context, args)
    }
  }
}

# 应用场景:

  • scroll 事件
  • 搜索框实时搜索

对于搜索联想词这种情况,用防抖节流都能实现,但个人偏向使用节流。

下面我们看下百度的联想词搜索,几乎是在用户输入的同时就在请求接口了:

搜索联想词这种实时性要求较高。

使用防抖来模拟实现搜索联想词:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" onkeyup="debounceSearch()" />
  <script>
    const debounceSearch = debounce(search, 500)

    function search() {
      ajax()
    }
    function ajax() {
      console.log('模拟联想词接口' + Date.now())
    }
    function debounce(fn, delay) {
      let timer = null;
      return function () {
        if (timer) clearTimeout(timer);
        const context = this;
        const args = arguments;
        timer = setTimeout(function() {
          fn.apply(context, args)
        }, delay)
      }
    }
  </script>
</body>
</html>

效果如下:

可以看到当用户一直在输入的时候,搜索词联想接口并没有及时调用,用户得不到良好的反馈。当然,你可以说你把时间改短点呀,这当然是个方法,我们甚至可以把时间设置为 0,但这样还要防抖干啥呢,直接写不好吗。除了减少时间这种方式,我们还可以使用防抖的优化版本。

使用节流来模拟实现搜索联想词:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" onkeyup="throttleSearch()" />
  <script>
    const throttleSearch = throttle(search, 500)

    function search() {
      ajax()
    }
    function ajax() {
      console.log('模拟联想词接口' + Date.now())
    }
    function throttle(fn, interval) {
      let last = 0;
      return function() {
        const context = this;
        const args = arguments;
        const now = Date.now();

        if (now - last >= interval) {
          last = now;
          fn.apply(context, args);
        }
      }
    }
  </script>
</body>
</html>

效果如下:

可以看到虽然用户一直在输入,接口也相对实时的调用了,接口调用的不那么频繁也可以给用户一个更好的反馈。