10

概述

在平时的开发中,经常会听到两个差不多很相近的词。节流(throttle)和防抖(debounce)。这是两个类似又有些不同的优化方案。

节流:在指定时间之内,让函数只触发一次。
防抖:对于一定时间段的连续的函数调用,只让其执行一次。

两个方法在underscore.js中都已经实现了。本文将会重点说明两个函数的应用场景和背后的原理。

应用场景

节流

throttle在英语里的意思是节流阀,顾名思义,设置一个阀值(制定一个时间),在这个阀值或者时间之内,函数只会执行一次。

举个例子,我们执行页面滚动的时候,比如在react里面,可能每次滚动都会触发一次render,这样严重影响性能,甚至会造成浏览器卡死。如果我们设置一个300ms的时间阀,那么在这段时间内,滚动时候只会触发一次render.

同样的,当我们拖拽某个元素的时候,会每次判断mousemove时跟位置相关的信息,每次都会执行相关的计算和判断,这种情况就和滚动时候一样,如果设置一个时间阀,那么就可以避免由于大量执行事件计算而造成的性能下降。

防抖

我自己的理解,防抖的意思可以认为是,阻止连续的抖动(所谓的事件触发),也就是说,我们用防抖来让那些连续触发的事件只触发一次。

比如,当我们对一个文本框进行输入的时候,在react中,每次都会触发onChange事件,我们可能在每次事件里发送ajax请求,判断输入的用户名是否曾经注册过,这种情况下我们使用防抖,可以保证只会在最后一次onChange事件才会触发ajax请求。

实现原理

节流

节流实现起来很好理解,设置一个bool值,在时间阀之内,根据这个bool来判断是否执行函数。

function throttle(fn,times = 300){
    let bool = true
    return function(){
        if(!bool){
            return false
        }
        bool = false
        setTimeout(()=>{
            bool = true
            fn.apply(this,arguments)
        },times)
    }
    
}

防抖

防抖实现起来的思路是,用闭包保存执行的函数,多次执行的时候把上一个执行的函数清除掉,然后再次创建一个新的函数。这样在间隔时间内还有事件触发的话,不会执行之前的函数,这么一来,函数真正的执行就是最后一次事件触发。

function debounce(fn,times){
    let timeout = null
    return function(){
        clearTimeout(timeout)
        timeout = setTimeout(()=>{
            fn.apply(this,arguments)
        },times)
    }
}

总结

以上只是很简单的写了一下节流和防抖的原理,在underscore.js里,实现起来更加复杂,但是背后的原理核心就是上边代码写的。两者都是在密集调用的过程中灵活使用setTimeout函数来对频繁触发的事件进行控制和优化。


张小草1018
285 声望8 粉丝