javascript之函数防抖与节流

790 阅读2分钟

  平时我们自己在开发过程中可能需要监听窗口的大小(resize等)来调节样式,或者是根据鼠标移动(mousemove等)来执行相应的方法,以及键盘按键(keyup等)事件。但是这里会产生一个问题——频繁改变窗口大小和移动鼠标会导致前端页面被频繁渲染,有时候可能导致页面崩溃。页面渲染过程中也就是dom被操作的过程,而dom操作越频繁,对前端的性能影响就越大,前端性能也越差,所以大神们就总结除了函数防抖和节流这两种解决页面被过渡渲染导致性能低下的问题。 所以在此记录下以供将来复习,同时也能够通过这些文章来了解到自己哪些时间段学习过什么内容。

1、函数防抖

原理:函数执行过一次后,在等待时间段内不能再次执行。 在等待时间内触发此函数,则重新计算等待时间。

代码实现

    /*
    *fn:要防抖的函数
    *wait:要等待的时间
    *immediate:是否立刻执行fn函数
    */
    function debounce(fn,wait,immediate){
        let timer=null; 
        let _debounce=function(){
            //判断定时器是否存在,存在即删除定时器
            timer&&clearTimeOut(timer);
            //是否立刻执行
            if(immediate){
                //定时器不存在时,才回去执行函数
                !timer&&fn.apply(this,arguments)
                timer=setTimeOut(()={
                    timer=null;
                    //过了await时间后,fn才可以被再次执行
                },await)
            }else{
                timer=setTimeOut(()=>{
                    //过了await时间后,再次设置的定时器才不会被清除
                    timer=null;
                    fn.apply(this,arguments);
                    //arguments为调用fn函数传入的参数
                },await)
            }
        }
        //取消
        _debounce.cancel=()=>{
            timer=null;
            clearTimeOut(timer);
        }
        return _debounce;
    }
    //应用
    document.onmousemove=debounce(function(e){
        console.log("鼠标移动了");
        console.log(new Date().getUTCSeconds());
        console.log(e);//e是事件对象,
    },300,true);

输出结果如下:

2、函数节流

原理:节流就是在让函数在特定的时间内只执行一次(持续触发事件,每隔一段时间,只执行一次事件)。

代码实现:

function throtle(fn,await){
    let timer=null;
    let previousTime=0;
    let _throtle=()=>{
        let now=+new Date();//获取当前时间戳
        let remain=now-previousTime
        if(remain>await){
            //下面的代码只会在第一次触发时执行(或者是间隔时间超过await后再次执行)
            if(timer){
                //清除定时器
                clearTimeOut(timer);
                timer=null
            }
            //此时now不等于+new Date()
            previousTime=+new Date();//当前时间,使用+获取当前时间戳
            fn.apply(this,...arguments);
        }else if(!timer){//避免添加多个定时器
            timer=setTimeOut(()=>{
               timer=null;
               previousTime=+new Date();//当前时间
               fn.apply(this,...arguments);
            },remain);
        }
    }
    _throtle.cancel=()=>{
        timer=null;
        clearTimeOut(timer);
        previousTime=0;
    }
    return _throtle;
}

参考链接:
1、一个合格的中级前端工程师必须要掌握的 28 个 JavaScript 技巧
2、函数防抖
3、javaScript专题之跟着underscore学防抖
4、javaScript专题之跟着underscore学节流