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

什么是防抖

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

那么防抖究竟是什么?

防抖(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绑定

总结

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

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

欢迎大家在评论区留言!

相关推荐
OpenTiny社区6 分钟前
Node.js技术原理分析系列——Node.js的perf_hooks模块作用和用法
前端·node.js
菲力蒲LY9 分钟前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis
MickeyCV1 小时前
Nginx学习笔记:常用命令&端口占用报错解决&Nginx核心配置文件解读
前端·nginx
祈澈菇凉2 小时前
webpack和grunt以及gulp有什么不同?
前端·webpack·gulp
十步杀一人_千里不留行2 小时前
React Native 下拉选择组件首次点击失效问题的深入分析与解决
javascript·react native·react.js
zy0101012 小时前
HTML列表,表格和表单
前端·html
初辰ge2 小时前
【p-camera-h5】 一款开箱即用的H5相机插件,支持拍照、录像、动态水印与样式高度定制化。
前端·相机
HugeYLH2 小时前
解决npm问题:错误的代理设置
前端·npm·node.js
三天不学习2 小时前
Redis面试宝典【刷题系列】
数据库·redis·面试
六个点3 小时前
DNS与获取页面白屏时间
前端·面试·dns