JS函数的节流和防抖

防抖(debounce): 触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行事件

非立即执行版本:触发事件后函数不会立即执行,而是在n秒后执行,如果在n秒内触发了事件则会重新计算函数执行时间。

/* 函数防抖 */
var inputDom = document.querySelectorAll("#debounce")[0];
/* 非立即执行防抖 */
var timer = null;
inputDom.addEventListener("input", function(){
    clearTimeout(timer);
    var self = this;
    var arg = arguments;
    clearTimeout(timer);
    timer = setTimeout(function(){
        //此处不能使用call,应该使用apply,直接将参数放在数组中传
        handle.apply(this, arg);
    }, 800)
});
function handle(ev){
    var ev = ev || window.event;
    console.log("ev:", ev);
}
/* 封装 */
function debounce(func, wait){
    let timer = null;
    return (function(){
        let self = this;
        let args = arguments;
        if(timer) clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(self, args)
        }, wait);
    })
}

立即执行版本:   触发事件后函数会立即执行,然后n秒内不触发事件才能继续执行函数的效果。

/* 立即执行防抖 */
var inputDom = document.querySelectorAll("#debounce")[0];
var timer;
inputDom.addEventListener("input", function(){
    if(timer) clearTimeout(timer);
    // 判断是否在等待时间内
    var callNow = !timer;
    timer = setTimeout(() => {
        // 等待一段时间后重置timer
        timer = null
    }, 1000);
    // 如果不在等待时间内,则调用事件处理函数
    if(callNow) handle.apply(this, arguments);
});
function handle(ev){
    var ev = ev || window.event;
    console.log("ev:", ev);
}
/* 封装版本 */
function debounce(handle, wait){
    let timer;
    return (function(){
        let self = this, args = arguments;
        
        if(timer) clearTimeout(timer);

        let callNow = !timer;
        timer = setTimeout(() => {
            timer = null;
        }, 1000);

        if(callNow){
            handle.apply(self, args);
        }
    });
}

双剑合璧版本:

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func,wait,immediate) {
    let timeout;

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

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(() => {
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

节流(throttle):指连续触发事件但是在n秒中只执行一次函数。节流会稀释函数的执行频率。

时间戳版本:

/* 节流 */
/* 时间戳版本 */
var inputDom = document.querySelectorAll("#debounce")[0];
var previous = 0;
inputDom.addEventListener("input", function(){
    var now = Date.now();
    if(now - previous > 1000){
        handle.apply(this, arguments);
        // 重置时间戳
        previous = now;
    }
});
function handle(ev){
    var ev = ev || window.event;
    console.log("ev:", ev);
}
/* 封装版本 */
function throttle(handle, wait){
    let previous = 0;
    return (function(){
        let now = new Date();
        let context = this;
        let args = arguments;
        if(now - previous){
            handle.apply(context, args);
            previous = now;
        }
    })
}

定时器版本:

/* 封装版本 */
function throttle(handle, wait){
    let timeout;
    return (function(){
        let context = this;
        let args = arguments;

        if(!timeout){
            timeout = setTimeout(() => {
                timer = null;
                handle.apply(context, args);
            }, wait)
        }
    });
}

时间戳版和定时器版的节流函数的区别是:时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。

双剑合璧版本:

/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle(func, wait ,type) {
    if(type===1){
        let previous = 0;
    }else if(type===2){
        let timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if(type===1){
            let now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }else if(type===2){
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }
    }
}

参考文献:https://www.jianshu.com/p/c8b86b09daf0

原文地址:https://www.cnblogs.com/jett-woo/p/12040419.html