js中的防抖和节流

154 阅读2分钟

防抖

对于连续触发的同一事件,我们对其做一个限制: 事件触发触发时,开始进行计时。当事件在一段时间之内不再触发时,再执行事件触发的后续操作。 当事件在时间限制之内再次触发时,重新计时。
使用场景:对于连续触发的同一事件,实际操作中只需要第一次触发或者最后一次触发。
有两种实现方式:非立即执行和立即执行
非立即执行

function debounce(func, wait) {
    let timer = null;
    return function () {
        let context = this;
        let args = arguments;
        if (timer) clearTimeout(timer);
        timer = setTimeout(function(){
            func.apply(context, args);
        }, wait)
    }
}

非立即执行:在事件触发时做一个计时,在时间限制之内事件没有再次触发,再接着执行后续操作
立即执行

function debounce(func, wait) {
    let timer = null;
    return function () {
        let context = this;
        let args = arguments;
        if (timer) clearTimeout(timer);
        let callnow = !timer;
        timer = setTimeout(function () {
            timer = null;
        }, wait);
        if (callnow) func.apply(context, args);
    }
}

立即执行:在事件触发之后执行所有代码并开始计时。在时间限制之内没有再次触发事件,计时结束后再次出发会再次执行。时间限制之内再次出发则重新计时。
两个函数可以合为统一个函数

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func, wait, immediate) {
    let timer = null;
    return function () {
        let context = this;
        let args = arguments;
        if (timer) clearTimeout(timer);
        if (immediate) {
            let callnow = !timer;
            timer = setTimeout(function () {
                timer = null;
            }, wait);
            if (callnow) func.apply(context, args);
        } else {
            timer = setTimeout(function () {
                func.apply(context, args);
            }, wait);
        }
    }
}

节流

对于连续触发的同一事件,对其触发后的操作做一个频率限制:控制其在一段时间限制内触发时只执行一次
使用场景:对于连续触发的同一事件,我们需要得到多次触发
有两种实现方式:时间戳版和定时器版
时间戳版

function throttle(func, wait) {
    let pervious = 0;
    return function () {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - pervious > wait) {
            func.apply(context, args);
            pervious = now;
        }
    }
}

定时器版

function throttle(func, wait) {
    let timer = null;
    return function () {
        if (!timer) return false;
        let context = this;
        let args = arguments;
        timer = setTimeout(function () {
            timer = null;
            func.apply(context, args);
        }, wait);
    }
}

二合一版本

/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 时间戳版,2 定时器版
 */

function throttle(func, wait, type) {
    if (type == 1) {
        let pervious = 0;
    } else if (type == 2) {
        let timer = null;
    }
    return function () {
        let context = this;
        let args = arguments;
        if (type == 1) {
            let now = Date.now();
            if (now - pervious > wait) {
                func.apply(context, args);
                pervious = now;
            }
        } else if (type == 2) {
            if (!timer) return false;
            timer = setTimeout(function () {
                timer = null;
                func.apply(context, args);
            }, wait);
        }
    }
}