手撕防抖节流(含原理与应用场景,以及为什么加apply)


防抖是事件停止触发且过了某指定时间后执行一次,而函数节流是间隔某指定的单位时间执行一次。(控制高频事件执行次数)

debounce防抖

事件被触发后延迟n秒再执行回调,如果在这n秒内又被触发,则重新计时。

实现

具体实现:原理就是利用闭包


inp.oninput = debounce(function (event){
console.log(this.vlaue);
},500)

 function debounce(fn, delay) {
        let timerId = null;
        return function (...args) {
            if (timerId) {
                clearTimeout(timerId);
            }
            timerId = setTimeout(() => {
            //fn()独立函数调用this就是window
            
            //这个this指向触发事件的对象
                fn.apply(this,args);
                timerId = null;
            }, delay);
        }
    }

在这里插入图片描述

场景

resize事件、scroll事件、用户输入input事件、拖拽事件、频繁的点击等

throttle节流

顾名思义就是每过n秒仅执行一次回调函数。如单位时间内多次触发函数,也只有第一次生效,相比防抖缺少了clearTimeout这一步骤,而是通过if语句判断

实现

// 节流函数
function throttle(fn, delay) {
    let timer = null;      //定义一个定时器
    return function(...args) {
        if(!timer) {
            timer = setTimeout(()=> {
                fn.apply(this, args);
                timer = null;
            }, delay);
        }
    }
}
// 原始函数
const scrollEvent = function() {
   console.log('当前时间戳:' + new Date().getTime());
}
// 两函数结合,实现节流防抖
const scrollHandler = throttle(scrollEvent, 1000)
// 滚动事件
window.addEventListener('scroll', scrollHandler);

在这里插入图片描述
由于setTimeout函数的时间参数存在误差(或者说执行函数本身所需要的时间),所以打印的结果后三位不一定是我们期望的数值。节流函数除了利用定时器的方式,也可以利用时间戳的方式。当前时间与上一个时间进行比对,相差结果是我们希望看到的。

场景

鼠标不断触发某事件时,如点击,只在单位事件内触发一次;
懒加载时要监听计算滚动条的位置,但不必要每次滑动都触发,可以降低计算频率,而不必要浪费CPU资源

关于其中的apply使用

在学习手撕节流防抖的过程中我发现两者都使用到了apply改变this指向,我产生了这样的疑惑——“直接调用不行吗,好像影响也不是很大”,然后查阅了相关的博客,可以得出这样的总结:

首先我们需要知道其用意,apply希望this指向哪里:
fun.apply(this,arguments)的用意,无非就是想fun中的this指向debounce中return的这个函数中的this,return回来的这个函数中的this也就是指向直接调用return 函数那个对象
为什么需要改变this呢,不改变不行吗:
上述例子中我们都可以知道,这里都是window来直接调用return回来的那个函数,所以apply与否都没差

而对于下面这种情况:
不改变的话出大问题,不改变的话指向undefined(严格模式下没有调用者时,this的值为undefined),加上apply后才指向实例。

class Foo {
  constructor() {
    this.a = "a";
    this.bar = debounce(this.bar, 500);
  }
  bar() {
    console.log(this.a);
  }
}
const foo = new Foo();
foo.bar();

如有不对欢迎探讨!

参考资料:
防抖和节流的区别和实现详解(中高级前端面试必备知识)
防抖/节流中的apply起到的作用
this指向,防抖函数中的fn.apply(this,arguments)作用

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值