防抖和节流,你会手写吗?(上)

什么是防抖

我们在前端工作中都会遇到频繁触发的事件处理问题,例如在短时间内多次点击页面上的提交按钮。而解决这类问题的一种常见方法就是使用防抖和节流技术。想象一下,你正在为一个在线搜索功能编写前端代码。用户提交按钮点击五六次,页面频繁地发起请求,这不仅影响了用户体验,还给服务器带来了不必要的压力。而在这种情况下,防抖和节流技术就像是一把,能够有效地解决这个问题。

那么防抖究竟是什么?

防抖(Debouncing)是一种常用的前端优化技术,用于处理频繁触发的事件,如浏览器窗口的调整大小、滚动等,以及用户输入的事件,如键盘输入、鼠标移动等。

在防抖技术中,当事件被触发后,不立即执行相应的处理函数,而是等待一段时间(称为防抖延迟期间),如果在这段时间内没有再次触发相同的事件,那么才执行相应的处理函数。如果在延迟期间内又触发了相同的事件,则重新开始计时,直到没有再次触发事件才执行处理函数。那么简单来说防抖就是在规定的时间内没有第二次的操作,才执行逻辑

手写防抖

那么下面是完整的防抖实现代码:

function debounce(fn, delay){
            let timer;

            return function(){ 
                //使用arguments关键字
                let args = arguments

                if(timer) clearTimeout(timer) //取消定时器
                timer = setTimeout(() => {
                    //显式绑定
                    fn.call(this,...args)
                },delay)
            }
        }

那么我们来分析上述的代码:

防抖函数接受两个参数,fn是事件触发时真正需要调用的函数,也就是目标函数,delay是防抖延迟时间。

timer变量用于设置一个延时执行的定时器,args变量存储类数组arguments,因为事件触发的回调函数接受的参数是未知的,所以用类数组表示不定的参数,clearTimeout方法用来取消定时器,达到重新计时的作用。.call(this) 显式地指定了函数 fn 的执行上下文,即调用防抖函数时的执行上下文,这样可以确保在防抖函数内部执行 fn 函数时,fn 函数中的 this 引用的是正确的对象。

那么防抖代码的主要实现逻辑是什么?我将用一个实例让大家轻松理解!

        let btn = document.getElementById('btn')
        function send(e){
            console.log(this,'提交完成',e);
        }
        btn.addEventListener('click' , debounce(send,1000))

        function debounce(fn, delay){
            let timer;

            return function(){ //闭包
                let args = arguments
                
                if(timer) clearTimeout(timer) //取消定时器
                timer = setTimeout(() => {
                    //显式绑定
                    fn.call(this,...args)
                },delay)
            }
        }

上述代码实现的是对一个提交按钮进行防抖优化。主要作用是防止用户短时间内点击多次button按钮

分析:

当用户点击button按钮,调用debounce函数,并传入两个参数,目标函数send和防抖延迟时间1000ms,那么debounce函数会返回出一个函数,所以当按钮被点击时,实际上会执行 debounce 返回的函数,而不是send函数,且该函数是一个闭包函数,用于写防抖的逻辑,且闭包保存了fn、delay、timer

执行闭包函数的逻辑时,先判断timer是否为空,很明显如果在防抖延迟时间内,点击了第二次按钮,就会将定时器timer清除,重新设置新的定时器。如果没有,则执行定时器中的回调函数,也就是调用send函数,并传入原始函数的参数。

但是一定要注意两点:

1. send函数的参数是不定的,所以用arguments类数组去保存send函数的参数,然后用解构的形式也就是展开运算符...来传参。

2. send函数的this指向可能出问题,(如果是小白不了解this的绑定规则的话可以参考这篇文章:(JS)15分钟带你彻底跨越JS的一座大山–this),那么我们通过使用 call 方法将 this 显式绑定到当前(闭包函数)上下文。注意定时器中的回调函数是一个箭头函数,没有this绑定

总结

防抖技术通过延迟执行事件处理函数,有效地控制了事件触发的频率,从而提升了页面性能和用户体验。

那么节流的目标与防抖是一样的,但是设计思路会与防抖略有不同,下节我将继续给大家带来节流的手写,让大家在面试时轻松化解手写的危机。

欢迎大家在评论区留言!

原文链接:https://juejin.cn/post/7342511044290641974 作者:UrGend

(0)
上一篇 2024年3月5日 下午5:05
下一篇 2024年3月5日 下午5:15

相关推荐

发表回复

登录后才能评论