JS函数防抖和节流

防抖(debounce):在指定的时间 n 秒后执行回调,如果在计算时间的过程中又被触发,则从新开始计算时间

function debounce(fn, wait, immediate) {

    let timer = null;

    //  返回一个函数

    return function(...args) {

        // 每次触发事件时都取消之前的定时器

        clearTimeout(timer);

        // 判断是否要立即执行一次

        if(immediate && !timer) {

            fn.apply(this, args);

        }

        // setTimeout中使用箭头函数,就是让 this指向 返回的该闭包函数,而不是 debounce函数的调用者

        timer = setTimeout(() => {

            fn.apply(this, args)

        }, wait)

    }

}

使用场景:

监听resize或scroll,执行一些业务处理逻辑

window.addEventListener('resize', debounce(handleResize, 200));

window.addEventListener('scroll', debounce(handleScroll, 200));

使用到一些高频触发的函数,需要考虑防抖

window 的 resize、scroll

mousedown、mousemove

keyup、keydown ...

搜索输入框,在输入后200毫秒搜索

debounce(fetchSearchData, 200);


节流(throttle): 在指定时间 n 秒内只执行一次回调,如果在计算时间过程内被多次调用则只有一次生效

使用时间戳

function throttle(fn, wait)  {

    // 记录上一次执行的时间戳

    let previous = 0;

    return function(...args) {

        // 当前的时间戳,然后减去之前的时间戳,大于设置的时间间隔,就执行函数,否则不执行

        if(Date.now() - previous > wait) {

            // 更新上一次的时间戳为当前时间戳

            previous = Date.now();

            fn.apply(this, args);

        }

    }

}

第一次事件肯定触发,最后一次不会触发(比如说监听 onmousemove,则鼠标停止移动时,立即停止触发事件)

使用定时器

function throttle(fn, wait)  {

    // 设置一个定时器

    let timer = null;

    return function(...args) {

        // 判断如果定时器不存在就执行,存在则不执行

        if(!timer) {

            // 设置下一个定时器

            timer = setTimeout(() => {

                // 然后执行函数,清空定时器

                timer = null;

                fn.apply(this, args)

            }, wait)

        }

    }

}

第一次事件不会触发(fn是放在 setTimeout中执行的,所以第一次触发事件至少等待 wait 毫秒之后才执行),最后一次一定触发



使用时间戳加定时器

两个结合则第一次和最后一次都会被触发

function throttle(fn, wait)  {

    // 记录上一次执行的时间戳

    let previous = 0;

    // 设置一个定时器

    let timer = null;

    return function(...args) {

        // 当前的时间戳,然后减去之前的时间戳,大于设置的时间间隔

        if(Date.now() - previous > wait) {

            clearTimeout(timer);

            timer = null

            // 更新上一次的时间戳为当前时间戳

            previous = Date.now();

            fn.apply(this, args);

        } else if(!timer) {

            // 设置下一个定时器

            timer = setTimeout(() => {

                timer = null;

                fn.apply(this, args)

            }, wait)

        }

    }

}

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