防抖节流从理解到封装

217 阅读2分钟

1,防抖和节流是什么有什么区别

标题防抖节流
定义防止事件一直高频率触发,
在高频率触发时选择只执行最后一次
防止事件一直高频率触发,
在高频率触发时限制按照固定频率执行
使用场景监听输出框触发事件
改成光标离开输出框时触发
window.scroll
核心区别清除定时器clearTimeout(timer);判断触发频率是否高于当前设置的wait

2,简单实现写防抖节流方法

2.1 频繁点击btn按钮,添加防抖功能,频率超过200s时只执行一次

==>默认事件

btn.onclick = function(){
    console.log("触发点击事件");
}

==>加上防抖功能

let timer;
btn.onclick = function(){
    clearTimeout(timer);
    timer = setTimeout(()=>{
        console.log("触发点击事件");
    },200)
}

==>简单封装

const debounce = function debounce(func,wait){
    let timer=null;
    return function(){
        clearTimeout(timer);
        timer = setTimeout(()=>{
            func.call(this) //console.log("触发点击事件");
        },wait)
    }
}
function f(){
    console.log("触发点击事件");
}
btn.onclick = debounce(f,200);
2.2 给屏幕滚动时间添加限流

==>原始方法

window.onscroll = function(){
    console.log("屏幕滚动");
}

==>加上节流功能

let timer = null;
window.onscroll = function(){
    let flag = true;//首次触发可以调用
    if(flag){
        flag = false;//一旦触发就立刻限制触发
        clearTimeout(timer);//清空定时器
        timer = setTimeout(()=>{
            console.log("屏幕滚动");
            flag = true;//执行后解除限制 
        },200)
    }
}

==>简单封装节流功能

const throttle = function throttle(func,wait){
    let timer = null
    return function(){
        let flag = true;
        if(flag){
            flag = false;
            clearTimeout(timer);
            timer = setTimeout(()=>{
                func.call(this);
            },wait)
        }
    }
}
function fn(){
    console.log("屏幕滚动");
}
window.onscroll = throttle(fn,200);

3,高级封装 封装一个util组件

(function(){
    const clearTimer = function clearTimer(timer){
        if(timer!=null){
            clearTimeout(timer);
        }
        return null;
    }
    /**
     * 防抖
     * @param {Function} func 
     * @param {Number} wait 
     * @param {Boolean} immediate 
     * @returns function 
     */
    const debounce = function debounce(func,wait,immediate){
        //init param
        if(typeof func!=='function') throw TypeError('func is not a function');
        if(typeof wait ==='boolean') immediate = wait;
        wait = +wait;
        if (isNaN(wait)) wait=300;
        if(typeof immediate!=='boolean') immediate =false;
        //handler
        let timer = null;
        return function operate(...params){
            let now = !timer && immediate;//是否立即执行 
            timer = clearTimer(timer);//清空timer
            timer = setTimeout(()=>{
                if(!immediate) func.call(this,...params);
                timer = clearTimer(timer);
            },wait)
            if(now) { console.log(now);func.call(this,...params);}
        }
    }
     /**
     * 节流
     * @param {Function} func 
     * @param {Number} wait 
     * @returns function 
     */
    const throttle = function throttle(func,wait){
        //init parm
        if(typeof func !== 'function') throw TypeError('func is not a function')
        wait = +wait;
        if(isNaN(wait)) wait =300;
        let timer=null, preDate = 0;
        //handler
        return function operate(...param){
            let now = +new Date(),
            diff = wait - (now - preDate);
            if(diff<=0){//触发频率低于wait,就是正常操作立即执行即可
                func.call(this,...param);
                preDate =  +new Date();
            }else if(!timer){//触发频率高于wait,设置限流
                clearTimer(timer)
                timer = setTimeout(()=>{
                    func.call(this,...param);
                    preDate =  +new Date();
                },diff)
            }
        }
    }

    const utils = {
        debounce,
        throttle
    }

    window.utils =_UT =  utils
})()