趣谈节流防抖,再不会出来挨打

很多小伙伴应该眼熟这两个词,节流、防抖无外乎是面试官最爱的问题之一,今天就让我们来好好谈一谈这个问题吧~

食用场景

先来看看这个问题的意义何在叭,其实工作中有很多都会用到节流防抖的场景,比如

  • 输入框搜索响应(特别是请求远程服务器资源的时候 )
  • 秒杀系统里的某个抢购按钮
  • 文档或者编辑器里自动保存的功能

之类的,其实本质都是减少触发执行函数的次数啦

防抖

事件被触发一定时间后再执行回调。如果在这段时间内又被触发了,则重新开始计算时间。

简单理解就是,如果这个单位时间内触发多次函数,只有一次生效

啥时候“抖”完了啥时候再执行呗

来看代码会更方便大家伙们理解(手写一个防抖(debounce)函数)

function debounce(fn, delay = 200) {
    let timer = 0;
  
    return function () {
        if (timer) clearInterval(timer)
  
        timer = setTimeout(() => {
            fn.apply(this, arguments); //  透传 this 和参数
            timer = 0;
        }, delay)
  
        console.log('timer', timer);
    }
}
let input = document.getElementById('input');
input.addEventListener('keyup', debounce(() => {
    console.log('触发防抖');
}, 300))

实现一个手写的防抖函数其实不难,分析一下上面的代码,我们先定义了一个timer用来计算触发次数

如果在同一个delay内触发函数多次,那么就每次都将内部的timer置零

只执行最后触发的那一次,以达成防抖的目的

其中有一个apply,我们都知道,apply函数是能够改变this指向的

apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或一个类数组arguments)的形式提供的参数。

常见的类数组对象:函数的arguments对象,浏览器的NodeList等

我们在这里借用apply函数的这个特性来透传this

让this指向debounce,以取得调用函数时传过来的参数

节流

那么节流的定义是什么呢

节流是每隔一段时间就执行一下回调,在过程中执行的。

可以这么理解,就是每隔一段时间,有规律地控制函数触发执行的次数,而不是像防抖一样,等到抖完了才去执行函数,节流函数是执行过程中就可以控制的

function throttle(fn, delay = 100) {
    let timer = 0;
    return function () {
        if (timer) return
        timer = setTimeout(() => {
            fn.apply(this, arguments)
            timer = 0
        }, delay)
    }
}

原理和防抖类似,节流函数的执行逻辑与防抖的区别无外乎在于一个是每隔一段时间就执行一下回调,另一个是结束了抖动(也就是你疯狂在输入框里面打字)的操作时,才触发的回调

防抖和节流的区别

其实前面已经说了,这里就浅浅总结一下几点区别

  • 节流:限制执行频率,有节奏地执行
  • 防抖:限制执行次数,多次密集的触发只执行一次
  • 节流关注过程,防抖关注结果

对于上面的代码都是模拟实现的手写节流防抖函数,但是在实际的工作中,我们还是用lodash,也就是别人已经封装好的,实际工作中切勿自己造轮子,除非你实力超神吊打尤大那种

研究学习的话,多撕撕源码或者自己实现一下也是好的,大家根据自己的学习情况来就好