节流和防抖其实没那么高大上

发布时间:2019-01-03 作者:一点通


节流(throttle)和防抖(debounce)是JS中的两个概念,听上去挺高大上的,很多同学也望而却步了,加上这俩概念还很类似,所以也就更加懵了。接下来我们以实际的例子作为突破口,讲解一下这俩究竟有何用途以及区别。

场景1

一个文章页面,左侧是文章各级标题的导航,当滚动的时候需要高亮显示对应的标题菜单,这个时候我们就需要监听页面的滚动事件,我们会顺手写下这样的代码

window.onscroll = function(){
    highlightMenu()
}

看上去好像没什么问题,但是如果highlightMenu()这个方法中执行的操作比较耗资源的话,就会明显看到页面的卡顿,原因很简单,滚动的出发频率相当高,而高频率地执行耗资源的操作比如会引起性能问题。

那么这个时候我们如果在滚动过程中不是每次滚动都去执行操作,而是每隔500毫秒执行一次,也就可以解决上面的问题了,于是我们将上面的代码改造一下

var cando = true
window.onscroll = function(){
    if(!cando){
        return
    }
    cando = false
    setTimeout(function(){
        hightlightMenu()
        cando = true
    }, 500)
}

我们称上面的做法为节流,目的是在高频率的事件触发中,以稍大的事件间隔去执行操作,降低操作频率。

场景2

用户注册的时候会填写一个用户名,在用户输入用户名的过程中,我们可以主动发送请求到后端去验证当前的用户名是否已经被注册。

<input id="uid" onKeyUp="keyup()" />

var keyup = function(){
    // 将value发送给后端验证
}

如果哦用户想输入的用户名是username,那么实际上在连续输完整个字符串后已经发了7次验证请求了,很明显是存在问题的,因为用户只想知道username整个字符串是否被注册,而不是每输入一个字母就去验证。

所以本质上我们要解决的问题是,预测用户是否已经输入完成。我们可以认为,用户每停顿800毫秒以上的时间,就认为已经完成,然后再去验证。

<input id="uid" onKeyUp="keyup()" />

var timer
var keyup = function(){
    clearTimeout(timer)
    timer = setTimeout(function(){
        // 将value发送给后端验证
    }, 800)
}

上面我们利用setTimeoutclearTimeout打造了一个类似缓存滑动过期的机制,只要我们认为用户还在规定的时间间隔内触发事件,那么就会一直等待下去,这个就叫防抖

区别

讲完了两种场景,我们可以细想一下,这俩虽说都是为了防止高频率事件触发导致的性能问题,但确实是有区别的。

节流强调的是在事件触发期间,按照固定的时间间隔执行操作,不管有多快,我都每隔多久执行一次。

防抖强调的是在事件触发期间,事件在指定的时间间隔内再次触发就继续等待,否则就执行。

按照缓存过期的理解就是,节流绝对过期,而防抖滑动过期