6.防抖和节流

防抖/节流


一、什么是防抖和节流?

防抖:

当频繁地执行一个函数,只需在最后一次执行该函数后一个间隔时间触发一次该函数,即在一些应用场景中,如input框的模糊查询,其特点:

  • 持续触发不执行函数;
  • 最后一次触发完毕,后隔一段时间只执行一次该函数;

节流
当频繁的执行一个函数,不管触发该事件如何频繁,只在间隔指定时间触发一次该事件,触发仍旧是多次,但是间隔时间是认为设定的,其特点:

  • 持续频繁触发,不会按照触发频次执行;
  • 持续触发,指按照设定间隔时间执行,执行是多次的,达到节制频率的作用;

二、debounce函数

// 触发事件对应的函数
 function counter() {
        content.innerHTML = num++;
    };
    
// 防抖函数
function debounce(func, delay) {
  let timer = null;
  return function() {
  if(timer) clearTimeout(timer) 
  // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。
    timer = setTimeout(() => {
     // 通过apply方法改变this的作用域到func上,参数为该函数的argument参数对象
      func.apply(this, arguments)  
    }, delay)
  }
}

// 截流函数调用
content.onmousemove = debounce(counter,1000);

通过闭包的方式实现该防抖函数,debounce(counter,1000)的两个参数分别表示触发事件函数和触发间隔时间,最后注册到onmousemove事件上的函数,是debounce内部函数;

三、throttle函数

1.时间戳节流函数
  • 特点:只要当前点击时,距离上次时间触发事件间隔大于或者等于delay时间,就立即执行fn函数
// 触发事件对应的函数
 function counter() {
        content.innerHTML = num++;
    };
    
 // 节流函数   
function throttle(fn, delay) {
// 此处last参数在外部函数执行完毕会释放掉,但是在内部函数的作用域链中仍然保留其变量对象;
// 在内部函数赋值last之前,last变量都是不变的
  let last = 0
  return function () {
    let now = Date.now()
    if (now - last >= delay) {  
      last = now;
       // 利用apply方法指定fn函数的作用域,闭包中匿名函数作用域指向为window
       // 内部函数返回后,最后被window调用,apply方法指定作用域,同时将arguments参数代入
      fn.apply(this, arguments) 
    }
  }
}
// 节流函数用法
content.onmousemove = throttle(counter,1000);

注意: 第一次点击的时候,事件必触发,因为last = 0,所以第一次会满足触发条件

2.定时器节流函数
// 触发事件对应的函数
 function counter() {
        content.innerHTML = num++;
    };
    
 // 节流函数   
function throttle(fn, delay) {
  let timer = null
  return function () {
    let context = this;
    let args = arguments;
    if(!timer){
    	timer = setTimeout(function(){
    		fn.apply(context,args)
    		timer = null;
        },delay)
    }
  }
}

// 节流函数用法
content.onmousemove = throttle(counter,1000);Ï

注意: 最后一次点击时候,事件也会隔1秒才执行;

3.综合定时器和时间戳

要求: 第一次点击不触发事件,最后一次点击立刻触发事件;

可以结合时间戳和定时器方法,即在首次点击的时候用定时器方法,在后面的点击事件中使用时间戳方法;
如下,remainning>0时,定时器方法会被执行,但是延时为remianning,因此每次点击都会clearTimeout(timer),实际最后执行的还是remianning<=0时的函数;
此时remainning<=0对应的是时间戳函数;于是只有在首次才会执行定时器函数;

function throttle(fn, delay) {
	// 设置定时器
    let timer = null;
    // 设置时间戳,表示每次点击事件的时间
    let startTime = Date.now();
    return function () {
    	// 当前时间
        let curTime = Date.now();
        // delay为节流时间间隔,curTime为当前时间,startTime此时表示上次的事件执行时间
        let remainning = delay -(curTime - startTime)
        let context = this;
        let args = arguments;
        clearTimeout(timer)
        if (remainning <= 0) {
        // 如果此时点击时间和上次触发事件时间间隔大约等于delay时间,则执行fn函数;
        // 并重新给startTime赋值新的触发事件时间
            fn.apply(context, arguments)
            startTime = Date.now();
        } else {
            timer = setTimeout(fn, remainning);
        }
    }
}

总结

  • 节流防抖函数通过闭包,将内部函数return出去,给到window去调用,注意window最后调用的是内部函数,而外部函数在第一次执行完毕,外部函数所占内存就被释放掉,但是因为作用域链特性,内部函数仍然可以访问外部函数的变量对象,并且可以修改变量值,因此外部函数中的变量可以用来存储上一次点击事件触发的时间
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值