大家都会的防抖与节流

这一篇文章我想写一下防抖与节流,由于我本身不是很理解并且说实话,之前知道,可是老忘,虽然概念还有一些简单的写法会,但仍是缺少练习和深入的理解。app


当咱们不加防抖或节流的时候就像这样,鼠标滑过触发这么屡次,因此咱们一个使用防抖或节流来限制它的请求次数而不是触发次数。关于防抖与节流的应用和解释自行查找资料。函数

<div id="app"></div>
function fn(e) {
    console.log(this);
    console.log(e);
    app.innerHTML = num ++;
}

1.防抖this

  • 简单实现
function debounce(fn, delay) {
    let timer = null;
    return function(){
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn();
        }, delay);
    }
}

使用节流后spa

app.onmousemove = fdebounce(fn, 1000);


咱们发现次数减小了太多,由于只要你在delay时间内不停地触发就不会执行直到你的间隔时间大于delay才会执行。3d

咱们来看一下this和event。

this是window,event是undefined。code

  • 修复this指向和事件参数
function debounce(fn, delay) {
    let timer = null,
        that;
    return function(e){
        that = this;
        clearTimeout(timer);
        timer = setTimeout(function () {  //this指向window(非严格模式)
            fn.apply(that, [e]);
        }, delay);
    }
}

或者是blog

function debounce(fn, delay) {
    let timer = null;
    return function(e){
        clearTimeout(timer);
        timer = setTimeout(()=>{ //箭头函数
            fn.apply(this, [e]);
        }, delay);
    }
}

  • 加强版(是否当即执行)
function debounce(fn, delay, immediate) {
    let timer = null,
        that; 
    return function (e) {
        that = this;
        clearTimeout(timer);
        if(immediate){  //是否当即执行
            if(!timer){  // 若是没有设置定时器就先执行
                fn.apply(that, [e]);
            }
            timer = setTimeout(function () { 
                timer = null;// 设置定时器,使其在delay毫秒内不能执行,过了delay毫秒后在执行
            }, delay);
        }else{ //不然延时执行
            timer = setTimeout(function () {
                fn.apply(that, [e])
            }, delay);
        }
    };
}
//这个if...else只能执行一个,要不先执行,要不延时执行


一开始会执行一次,由于录制不能显示鼠标因此理解一下。事件

  1. 节流
  • 简易版(时间戳)
function throttle(fn, delay) {
    let last = 0, //上次执行时间
        now; //执行时的时间
    return function (e) {
        now = Date.now(); //当前时间
        if(now - last >= delay){  //若是两次时间间隔大于delay,就执行
            last = now; //从新赋值
            fn(); 
        }
    };
}


在规定时间delay毫秒内总会执行一次事件。rem

  • setTimeout版本(修复this指向和事件参数)
function throttle(fn, delay) {
    let that,
        timer = null;
    return function (e) {
        that = this;
        if(!timer){  //若是没设置定时器就执行
            timer = setTimeout(function () {
                fn.apply(that, [e]);
                timer = null; //果delay毫秒就设置timer,这样就能delay执行一次
            }, delay);
        }
    };
}
  • 修复this指向和事件参数(时间戳)
function throttle(fn, delay) {
    let last = 0, //上次执行时间
        now; //执行时的时间
    return function (e) {
        now = Date.now(); //当前时间
        if(now - last >= delay){  //若是两次时间间隔大于delay,就执行
            last = now; //从新赋值
            fn.apply(this, [e]); 
        }
    };
}
  • 区别it

    • 时间戳版本的会先执行
    • setTimeout版本的会后执行

因此能够结合一下他们两个。

  • 结合版
function throttle(fn, delay) {
    let last = 0,  //上次执行时间
        now, //当前时间
        leftTime, //剩余时间
        that, 
        timer = null;
    return function (e) {
        that = this;
        now = Date.now();
        leftTime = delay - (now - last); 
        if(leftTime <= 0){ //保证一开始就执行(先执行)
            last = now;
            fn.apply(that, [e]);
        }else{
            timer = setTimeout(function() {  //延时执行
                fn.apply(that, [e]);
                timer = null;
            },delay)
        }
    };
}

这样作整体思路没错,可是第一次会执行之后就是两个一块儿执行,由于条件都知足。

  • 修改
function throttle(fn, delay) {
    let last = 0,
        now,
        leftTime,
        that,
        timer = null;
    return function (e) {
        that = this;
        now = Date.now();
        leftTime = delay - (now - last);
        if(leftTime <= 0){
            if(timer){ //若是有定时器就清除
                clearTimeout(timer);
                timer = null;
            }
            last = now;
            fn.apply(that, [e]);
        }else if(!timer){
            timer = setTimeout(function() {
                last = now; //若是时间知足就让他不知足
                //总之除了第一次就只让其中一个执行
                fn.apply(that, [e]);
                timer = null;
            },delay)
        }
    };
}

一开始执行一次(时间戳),最后中止在执行一次(setTimeOut)。

相关文章
相关标签/搜索