JS之防抖节流原理

35 阅读2分钟

64c1eaa9283720a59b034ae796c3e53.png

在日常前端开发中我们经常会遇到一些频繁的事件触发,例如: window中的resizescroll; mousedownmousemove; keyupkeydowm

函数防抖

n秒后再执行执行该事件,如果在该事件触发的n秒内它又再一次触发了这个事件,那就以新时间的时间为准,n秒后才执行

函数节流

n秒内只执行一次,如果在n秒内持续重复触发该事件,只有一次生效,即只执行一次事件

如何实现

防抖

** 简单实现 **

 function debounce(func, wait) {
    let timeout;
    
    return function() {
        //保存地址指向
        let context = this;
        //拿到event对象
        let args = arguments;
        
        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
 }

** 如果需要立即执行,可加入第三个参数用于判断 **

function debounce(func, wait, immediate) {

    let timeout;

    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout); // timeout 不为null
        if (immediate) {
            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 throttle1(func, wait) {
        var context, args;
        var previous = 0;

        return function() {
            var now = +new Date();
            context = this;
            args = arguments;
            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }
    }

** 使用定时器 **

    function throttle2() {
        var timeout;
        var previous = 0;
        
        return function() {
            context = this;
            args = arguments;
            if (!timeout) {
                timeout = setTime(function() {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }
    }

** 二者结合版 **

    function throttled3() {
        let timer = null;
        let starttime = Date.now();
        
        return function() {
            //当前时间
            let curTime = Date.now();
            //从上一次到现在,还剩下多少多余时间
            let remain = delay - (curTime - startTime);
            let context = this;
            let args = arguments;
            clearTime(timer);
            if (remaining <= 0) {
                fn.apply(context, args);
                startTime = Date.now();
            }
            else {
                timer = setTimeout(fn, remaining)
            }
        }
    }

** 总结**

  • 二者都可以通过使用 setTimeout 实现
  • 目的都是,降低回调执行频率。节省计算资源

** 区别**

  • 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout和 setTimeout实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  • 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次

** 应用场景**

防抖在连续的事件,只需触发一次回调的场景有:
  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流在间隔一段时间执行一次回调的场景有: