防抖和节流

2,069

前端开发中,我们的一些事件的响应比较慢或者需要请求接口完成的,我们不希望这些事件频繁执行,比如说需要对input输入的数据保存,监听keyup事件,如果每次键盘输入就执行保存请求,那样可能会产生很多频繁的请求,针对这种连续触发的高频率事件,函数防抖和函数节流给出了两种解决方法

防抖(debounce)

去抖动,方法是在函数触发时,设定一个周期延迟执行函数,若在周期内函数再次执行、则刷新延迟时间,直到最后执行函数,这里函数收集到的结果是最后一次操作的结果

简单的实现

var timer; // 定时器
function change (e) {
    if (timer) {
        clearTimeout(timer);
    }
    timer = setTimeout(function () {
        console.log(e.target.value);
        timer = void 0;
    }, 1000)
}
document.querySelector("#test").addEventListener('keyup', change);

这里监听input的keyup事件,change方法执行的时候会首先判断定时器是否存在、如果存在则clear掉,如果不则新建一个定时器延迟1s执行

封装

上面这样实现没毛病,但是却有一个问题,没有复用性,现在我来把他封装成一个公共的方法

function keyup (e) {
    console.log(e.target.value);
}

function debounce (method, delay) {
    var timer = void 0;
    return function () {
        var self = this;
        var args = arguments;
        timer && clearTimeout(timer);
        timer = setTimeout(function () {
            method.apply(self, args)
            timer = void 0;
        }, delay)
    }
}
document.querySelector("#test").addEventListener('keyup', debounce(keyup, 1000));

节流(throttling)

节流的概念是设定一个周期,周期内只执行一次,若有新的事件触发则不执行,周期结束后又有新的事件触发开始新的周期

实现

比如说我们监听onscroll判断获取当前的scrollTop、可以用到节流

var start, timer, wait = 200
function scroll() {
    var self = this;
    var args = arguments;
    if (!start) {
        //第一次触发,设置start时间
        start = Date.now()
    }
    // 当前时间减去开始时间大于等于设定的周期则执行并且初始化start、timer
    if (Date.now() - start >= wait) {
        console.log('触发了')
        start = timer = void 0;
    } else {
        timer && clearTimeout(timer)
        timer = setTimeout(function () {
            scroll.apply(self, arguments)
        },wait)
    }
}
document.addEventListener('scroll', scroll)

封装

function throttling (method, wait) {
    var start, timer
    return function run () {
        var self = this;
        var args = arguments;
        if (!start) {
            start = Date.now();
        }
        if (Date.now() - start >= wait) {
            method.apply(self, args)
            start = timer = void 0
        } else {
            timer && clearTimeout(timer)
            timer = setTimeout(function () {
                run.apply(self, args)
            }, wait)
        }
    }
}
function scroll() {
    console.log('触发了')
}
document.addEventListener('scroll', throttling(scroll, 200))

这里需要注意的就是参数和this指向的问题

总结

节流和防抖各有特点,如果是需要一连串频繁的事件只执行最后一次选择防抖、其它可以选择节流,具体业务具体分析

若文中有错误的地方望多多指正