资讯专栏INFORMATION COLUMN

你们都会的防抖与节流

beanlam / 1135人阅读

摘要:关于防抖与节流的应用和解释自行查找资料。修改如果有定时器就清除如果时间满足就让他不满足总之除了第一次就只让其中一个执行一开始执行一次时间戳,最后停止在执行一次。

这一篇文章我想写一下防抖与节流,因为我自己不是很理解而且说实话,以前知道,但是老忘,虽然概念还有一些简单的写法会,但还是缺乏练习和深刻的理解。


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

function fn(e) { console.log(this); console.log(e); app.innerHTML = num ++; }

1.防抖

简单实现

function debounce(fn, delay) {
    let timer = null;
    return function(){
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn();
        }, delay);
    }
}

使用节流后

app.onmousemove = fdebounce(fn, 1000);


我们发现次数减少了太多,因为只要你在delay时间内不停地触发就不会执行直到你的间隔时间大于delay才会执行。

我们来看一下this和event。

this是window,event是undefined。

修复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);
    }
}

或者是

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只能执行一个,要不先执行,要不延时执行


一开始会执行一次,因为录制不能显示鼠标所以理解一下。

节流

简易版(时间戳)

function throttle(fn, delay) {
    let last = 0, //上次执行时间
        now; //执行时的时间
    return function (e) {
        now = Date.now(); //当前时间
        if(now - last >= delay){  //如果两次时间间隔大于delay,就执行
            last = now; //重新赋值
            fn(); 
        }
    };
}


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

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]); 
        }
    };
}

区别

时间戳版本的会先执行

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)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101084.html

相关文章

  • 小菊花课堂之JS的防抖与节流

    摘要:文章来源详谈防抖和节流轻松理解函数节流和函数防抖函数防抖和节流好啦,今天的小菊花课堂之的防抖与节流的内容就告一段落啦,感各位能耐心看到这里。 前言 陆游有一首《冬夜读书示子聿》——古人学问无遗力,少壮工夫老始成。纸上得来终觉浅,绝知此事要躬行。,其中的意思想必大家都能明白,在学习或工作中,不断的印证着这首诗的内涵。所以,又有了此篇小菊花文章。 详解 在前端开发中,我们经常会碰到一些会持...

    leoperfect 评论0 收藏0
  • 小菊花课堂之JS的防抖与节流

    摘要:文章来源详谈防抖和节流轻松理解函数节流和函数防抖函数防抖和节流好啦,今天的小菊花课堂之的防抖与节流的内容就告一段落啦,感各位能耐心看到这里。 前言 陆游有一首《冬夜读书示子聿》——古人学问无遗力,少壮工夫老始成。纸上得来终觉浅,绝知此事要躬行。,其中的意思想必大家都能明白,在学习或工作中,不断的印证着这首诗的内涵。所以,又有了此篇小菊花文章。 详解 在前端开发中,我们经常会碰到一些会持...

    Yangder 评论0 收藏0
  • 前端笔记(二) 对象的深浅拷贝,函数的防抖与节流,函数柯里化 ,图片的预加载与懒加载

    摘要:对象是无法通过这种方式深拷贝。这就是函数防抖和节流要做的事情。函数防抖当触发频率过高时函数基本停止执行而函数节流则是按照一定的频率执行事件。 对象的深浅拷贝 对象的深拷贝与浅拷贝的区别: 浅拷贝:仅仅复制对象的引用, 而不是对象本身。 深拷贝:把复制的对象所引用的全部对象都复制一遍 浅拷贝的实现: var obj = { age : 18, person : { ...

    dongxiawu 评论0 收藏0
  • 高级函数技巧-函数防抖与节流

    摘要:封装方法也比较简单,书中对此问题也进行了处理使用定时器,让函数延迟秒后执行,在此秒内,然后函数再次被调用,则删除上次的定时器,取消上次调用的队列任务,重新设置定时器。 在实际开发中,函数一定是最实用最频繁的一部分,无论是以函数为核心的函数式编程,还是更多人选择的面向对象式的编程,都会有函数的身影,所以对函数进行深入的研究是非常有必要的。 函数节流 比较直白的说,函数节流就是强制规定一...

    whinc 评论0 收藏0
  • 函数防抖与函数节流

    摘要:函数节流保证如果电梯第一个人进来后,秒后准时运送一次,这个时间从第一个人上电梯开始计时,不等待,如果没有人,则不运行。 前言 有一些浏览器事件我们不希望它很频繁的触发,如调整窗口大小(onresize)、监听滚动条滚动(onscroll),如果这些监听事件需要调用接口的话一秒内可能会调用上百次,这样坑定是有问题的。 函数防抖(debounce) 如果有人进电梯(触发事件),那电梯将在1...

    novo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<