防抖节流

最新更新: 2021-08-16 13:46:47 阅读: 9次

防抖节流都是用于控制频繁触发的事件,如:鼠标移动事件、滚动事件,但其实它们两个有着本质的区别

debounce(防抖)这个事件是在你停止移动鼠标之后,触发一次;而throttle(节流)则是每隔一段时间触发一次。

防抖

防抖的原理则是不管你在一段时间内如何不停的触发事件,只要设置了防抖,则只在触发n秒后才执行。如果我们在一个事件触发的n秒内又触发了相同的事件,那我们便以新的事件时间为标准,n秒之后再执行。这里可以类比HDR照片:如果我们开启了HDR设置,那么在按下快门的一瞬间,相机会自动拍下非常多的照片,然后多张照片在最后合成最清晰的一张,也就是以最后那张为准。防抖同样如此,也是为了避免频发触发带来的性能问题,下面我们就来实现一个简单的防抖函数,如下:

                function debounce(callback, wait) {
                    let timeout;
                
                    return function () {
                        let context = this;
                        let args = arguments;
                
                        clearTimeout(timeout)
                        timeout = setTimeout(function(){
                            callback.apply(context, args)
                        }, wait);
                    }
                }
            

介绍完了简单的防抖函数,我们再思考如下一种场景,不想等到停止触发事件后才执行对应代码,而是希望立马执行代码;等到停止触发n秒后,然后再重新触发执行。这种如何写呢?我们可以设置一个字段offhand来判断是否立刻执行,代码如下:

                function debounce(func, wait, offhand) {
                    let timeout;
                
                    return function () {
                        let context = this;
                        let args = arguments;
                
                        if (timeout) clearTimeout(timeout);
                        if (offhand) {
                            let callNow = !timeout;
                            
                            timeout = setTimeout(function(){
                                timeout = null;
                            }, wait)
                            if (callNow) func.apply(context, args)
                        }
                        else {
                            timeout = setTimeout(function(){
                                func.apply(context, args)
                            }, wait);
                        }
                    }
                }
            

节流

节流的原理是不管你在一段时间内如何不断地触发事件,只要设置了节流,就会每隔一段时间执行一次。 我们可以用大坝来类比:在雨季水特别多的时候,我们肯定要打开整个水闸让水流的快一些;但是当旱季来临的时候,这个时候水资源严重匮乏,我们肯定不能直接关掉水闸,而是将水闸开的小一点,虽然流的慢,但是可以保持正常供应。那么节流就是这个道理,不能完成不触发的情况下,我们可以让它在一段时间内触发一次,这样就避免了频繁操作带来的性能问题。下面我们来实现一个简单的节流函数,如下:

使用定时器方式的节流函数

            function throttle(callback,wait){
                let timer;
                let previous=0
                return function(){
                    let context=this;
                    let args=arguments;
                    let now=+new Date();
                    if(now-previous>wait){
                        timer=setTimeout(function(){
                            timer=null;
                            callback.apply(context,args);
                            previous=now;
                        },wait)
                    }

                }
            }
           

使用定时器方式的节流函数

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