防抖函数-函数节流

应用场景

实际工作中,我们经常性的会通过监听某些事件完成对应的需求,比如:

  1. 通过监听 scroll 事件,检测滚动位置,根据滚动位置显示返回顶部按钮
  2. 通过监听 resize 事件,对某些自适应页面调整DOM的渲染(通过CSS实现的自适应不再此范围内)
  3. 通过监听 keyup 事件,监听文字输入并调用接口进行模糊匹配
  4. ...............

常规实现,以监听 scroll 事件为例

    window.onscroll  = function () {
        //滚动条位置
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
      console.log('滚动条位置:' + scrollTop);
    }

从效果上,我们可以看到,在页面滚动的时候,会在短时间内触发多次绑定事件。

我们知道DOM操作是很耗费性能的,如果在监听中,做了一些DOM操作,那无疑会给浏览器造成大量性能损失。

下面代码为设置防抖函数的:原理是对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时

    let timer;
    window.onscroll  = function () {
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(function () {
            //滚动条位置
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
            console.log('滚动条位置:' + scrollTop);
            timer = undefined;
        },200)
    }

防抖函数封装

/**
 * 防抖函数
 * @param method 事件触发的操作
 * @param delay 多少毫秒内连续触发事件,不会执行
 * @returns {Function}
 */
function debounce(method,delay) {
    let timer = null;
    return function () {
        let self = this,
            args = arguments;
        timer && clearTimeout(timer);
        timer = setTimeout(function () {
            method.apply(self,args);
        },delay);
    }
}

window.onscroll = debounce(function () {
    let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    console.log('滚动条位置:' + scrollTop);
},200)

通过上面的例子,我们知道我们可以通过函数防抖,解决了多次触发事件时的性能问题,比如,我们在监听滚动条位置,控制是否显示返回顶部按钮时,就可以将防抖函数应用其中。

但是但依然在有些功能场景中并不适用

比如:当我们做图片懒加载(lazyload)时,需要通过滚动位置,实时显示图片时,如果使用防抖函数,懒加载(lazyload)函数将会不断被延时,只有停下来的时候才会被执行,对于这种需要实时触发事件的情况,就显得不是很友好了。接下来就是我们要介绍的函数节流

函数节流

定义:触发函数事件后,短时间间隔内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。

原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。

    let startTime = Date.now(); //开始时间
    let time = 500; //间隔时间
    let timer;
    window.onscroll = function throttle(){
        let currentTime = Date.now();
        if(currentTime - startTime >= time){
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
            console.log('滚动条位置:' + scrollTop);
            startTime = currentTime;
        }else{
            clearTimeout(timer);
            timer = setTimeout(function () {
                throttle()
            }, 50);
        }
    }

我们可以封装一下函数

    /**
     * 节流函数
     * @param method 事件触发的操作
     * @param mustRunDelay 间隔多少毫秒需要触发一次事件
     */
    function throttle(method, mustRunDelay) {
        let timer,
            args = arguments,
            start;
        return function loop() {
            let self = this;
            let now = Date.now();
            if(!start){
                start = now;
            }
            if(timer){
                clearTimeout(timer);
            }
            if(now - start >= mustRunDelay){
                method.apply(self, args);
                start = now;
            }else {
                timer = setTimeout(function () {
                    loop.apply(self, args);
                }, 50);
            }
        }
    }
    window.onscroll = throttle(function () {
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        console.log('滚动条位置:' + scrollTop);
    },800)

另外一种封装

    /**
    * 节流函数
    * @param method 事件触发的操作
    * @param mustRunDelay 间隔多少毫秒需要触发一次事件
    */
    
    function Throttle (fn, delay = 500) {
        let self = fn 
        let timer = null
        let isFirst = false
    
        return function (...rest) {
            if (!isFirst) {
                self(...rest)
                return isFirst = true
            }
            
            if (timer) {
                return false   
            }
    
            timer = setTimeout(() => {
                clearTimeout(timer)
                timer = null
                self(...rest)
            }, delay)
        }
    }

你可能感兴趣的:(防抖函数-函数节流)