节流和防抖

170 阅读3分钟

区别

防抖: 只执行最后一次。事件持续触发,但只有等事件停止触发后 n 秒后才执行函数。

节流: 控制执行频率。持续触发,每 n 秒执行一次函数。

1. 节流:

简单来说就是: 单位时间内 频繁触发一个事件 只会触发一次
含义:顾名思义:一节一节的流,就好似控制水阀,在事件不断触发的过程中,固定时间内执行一次事件

在设置时间内 多次触发事件,只会在设定的时间结束后执行一次函数调用

实际应用:
  1. 点击按钮的触发
  2. 监听scroll滚动事件
实现方式(手写节流)

因为是固定时间内执行一次时间,所以我们有两种实现方法,一用时间戳,二用定时器。

时间戳:使用时间戳虽然能实现节流,但是最后一次事件不会执行。

    let pre = 0;
    return function (...args){
        if (new Date() - pre > wait) {
            // 当 n 秒内不重复执行
            pre = new Date();
            event.apply(this, args)
        }
    } 
}

定时器:使用定时器实现节流,虽然最后一次能触发,但是第一次不会触发。

function throttle(event, wait) {
    let timer = null;
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                timer = null;
                event.apply(this, args)
            }, wait)   
        }
    }
}

时间戳 + 定时器:(解决以上两个问题)

function throttle(event, wait) {
    let pre = 0, timer = null;
    return function (...args) {
        if (new Date() - pre > wait) {
            clearTimeout(timer);
            timer = null;
            pre = new Date();
            event.apply(this, args)
        } else {
            timer = setTimeout(() => {
                event.apply(this, args)
            }, wait)
        }
    }
}

节流实际应用场景

scroll 滚动

window.addEventListener('scroll', throttle(handleScroll, 200))

input 动态搜索

throttle(fetchInput, 300)

节流帝王库

  • lodash-throttle。
  • underscore-throttle。

2. 防抖

防抖就是要延迟执行,你一直操作触发事件一直不执行,当你停止操作等待多少秒后才执行

当你频繁触发一个事件时,就会引起不必要的性能损失,那么让该事件在停止触发后再触发,以此减少部分性能。

也就是说不管事件触发频率有多高,一定在事件触发 n 秒后执行。如果在事件触发的 n 秒又触发了这个事件,那就以新事件的事件为准,n 秒后才执行。总之,要等你触发完事件 n 秒内不再触发事件,它才执行。

含义:单位时间内 频繁触发一个事件,以最后的一次触发的为准

image.png

手写防抖

根据定义,我们知道要在时间 n 秒后执行,那么我们就用定时器来实现:

function debounce(event, wait) {
    let timer = null;
    return function (...args) {
      clearTimeout(timer); // 清除setTimeout,使其回调函数不执行
        timer = setTimeout(() => {
            event.apply(this, args)
        }, wait)
    }
}

代码很简单,即当还在触发事件时,就清除 timer,使其在 n 秒后执行,但此写法首次不会立即执行,为其健壮性,需加上判断是否第一次执行的第三个参数 flag,判断其是否立即执行。

function debounce(event, wait, flag) {
    let timer = null;
    return function (...args) {
        clearTimeout(timer)
        if (!timer && flag) {
            event.apply(this, args)
        } else {
            timer = setTimeout(() => {
                event.apply(this, args)
            }, wait)
        }
    }
}

防抖场景

窗口大小变化,调整样式

window.addEventListener('resize', debounce(handleResize, 200))

搜索框,输入后1000毫秒搜索

debounce(fetchSelectData, 300)

表单验证,输入 1000 毫秒后验证

debounce(validator, 1000)

防抖帝王库

两大工具库都有防抖源码,可供参考:

  • lodash-debounce。
  • underscore-debounce。