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

什么是防抖

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

那么防抖究竟是什么?

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

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

手写防抖

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

javascript 复制代码
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 引用的是正确的对象。

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

javascript 复制代码
        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绑定

总结

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

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

欢迎大家在评论区留言!

相关推荐
怕浪猫19 分钟前
GEO 优化到底是什么?AI时代内容创作者必须懂的新技能
算法·面试·github
沙漠之主4 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty4 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn5 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow6 小时前
ai agent --- 文件存储
前端
Frag0ut6 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT大白鼠6 小时前
搜索系列 · 第 08 篇——面试收官:高频题与全景总结
elasticsearch·面试·nosql
IT_陈寒7 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技7 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错7 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端