相同:在不影响客户体验的前提下,将频繁的回调函数,进行次数缩减。避免大量计算导致的页面卡顿。
不同:防抖是将多次执行变为最后一次执行,节流是将多次执行变为在规定时间只执行一次

函数防抖

函数防抖和节流 - 图1

防抖定义

指触发事件后在规定时间内回调函数只执行一次,如果在规定时间内又触发了该事件,则会重新开始算规定时间。
四字总结:延时执行

应用场景:

两个条件:
1,如果客户连续的操作会导致频繁的事件回调(可能引起页面卡顿).
2,客户只关心”最后一次”操作(也可以理解为停止连续操作后)所返回的结果.
例如:

  • 输入搜索联想,用户在不断输入值时,用防抖来节约请求资源。
  • 按钮点击:收藏,点赞,心标等。

    防抖的实现

    原理:
    通过定时器将回调函数进行延时.如果在规定时间内继续回调,发现存在之前的定时器,则将该定时器清除,并重新设置定时器.这里有个细节,就是后面所有的回调函数都要能访问到之前设置的定时器,这时就需要用到闭包(详见后面提到的)
  1. function debounce(func, wait) {
  2. let timeout;
  3. return function () {
  4. //通过this和argument获取函数的作用域和变量
  5. let context = this;
  6. let args = arguments;
  7. //清理掉正在执行的函数,并重新执行
  8. if (timeout) clearTimeout(timeout);
  9. timeout = setTimeout(() => {
  10. func.apply(context, args)
  11. }, wait);
  12. }
  13. }
  14. //如何调用
  15. var btn = document.getElementById("btn");
  16. btn.onclick = debounce(()=>{
  17. console.log(1)
  18. },1000)

防抖.gif
很明显,当连续点击按钮的时候,并不会一直打印输出1,因为防抖函数的原因,一段连续的点击中只有最后一次才是有效的。

函数节流

函数防抖和节流 - 图3

节流定义

当持续触发事件时,在规定时间段内只能调用一次回调函数。如果在规定时间内又触发了该事件,则什么也不做,也不会重置定时器
与防抖比较
防抖是将多次执行变为最后一次执行,节流是将多次执行变为在规定时间内只执行一次.一般不会重置定时器. 即不会if (timer) clearTimeout(timer);(时间戳+定时器版除外)

应用场景

两个条件:
1,客户连续频繁地触发事件
2,客户不再只关心”最后一次”操作后的结果反馈.而是在操作过程中持续的反馈.
例如:

  • 鼠标不断点击触发,点击事件在规定时间内只触发一次(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

注意 :何为连续频繁地触发事件,就是事件触发的时间间隔至少是要比规定的时间要短.
**

节流的实现

原理:
节流有两种实现方式

  1. 时间戳方式:通过闭包保存上一次的时间戳,然后与事件触发的时间戳比较.如果大于规定时间,则执行回调.否则就什么都不处理.
  • 特点:一般第一次会立即执行,之后连续频繁地触发事件,也是超过了规定时间才会执行一次。最后一次触发事件,也不会执行(说明:如果你最后一次触发时间大于规定时间,这样就算不上连续频繁触发了).
  1. 定时器方式:原理与防抖类似.通过闭包保存上一次定时器状态.然后事件触发时,如果定时器为null(即代表此时间隔已经大于规定时间),则设置新的定时器.到时间后执行回调函数,并将定时器置为null.
  • 特点:当第一次触发事件时,不会立即执行函数,到了规定时间后才会执行。 之后连续频繁地触发事件,也是到了规定时间才会执行一次(因为定时器)。当最后一次停止触发后,由于定时器的延时,还会执行一次回调函数(那也是上一次成功成功触发执行的回调,而不是你最后一次触发产生的)。一句话总结就是延时回调,你能看到的回调都是上次成功触发产生的,而不是你此刻触发产生的.
    • 说明: 这两者最大的区别:是时间戳版的函数触发是在规定时间开始的时候,而定时器版的函数触发是在规定时间结束的时候。 其他差异可以看我加粗的字. 具体理解请结合后面的代码实例, ```javascript //时间戳版 function throttle(func, wait) { var previous = 0; return function() { let now = Date.now(); let context = this; let args = arguments; if (now - previous > wait) {
      1. func.apply(context, args);
      2. previous = now;
      } } }

//定时器版 function throttle(func, wait) { let timeout; return function () { let context = this; let args = arguments; if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) }

  1. }
  2. }

``` 节流.gif
由上图可知,当连续点击按钮时,打印输出的时间间隔是相同的,不论点击多少次,在一定时间内,函数只执行那么多次。可以看到,在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次。