当前位置: 首页 > Web前端 > HTML

【跟着大佬学JavaScript】防抖

时间:2023-03-28 00:33:03 HTML

前言在前端开发中,会遇到一些频繁的事件触发,比如:windowresize,scrollmousedown,mousemove,mousewheel(鼠标滚轮)keyup(弹出thekeyboard),keydown(pressthekeyboard),keypress(pressthecharacterkeyboard)...想象一下窗口的调整大小事件或元素的onmouseover事件——当它们触发时,它们执行得非常快并且触发了很多次。如果你的回调很重,你可以杀死浏览器。这就是使用防抖的原因。原理防抖原理:在等待时间内,连续触发一个事件。第一种情况:如果一个事件在wait秒内触发了事件,应该以新的事件等待时间为准,wait秒后事件才会执行;第二种情况:如果事件触发wait秒后,如果事件没有触发,wait秒后直接执行事件。简单点说:定义wait=2000,连续点击按钮,点击前后的间隔在2秒以内,那么在最后一次点击按钮后,等待2秒再执行func方法。如果点击按钮,2秒后没有再次点击按钮,则2秒后直接执行func方法。示例代码代码1(根据原理)定义了函数debounce根据表达式可知需要传入参数:func,wait实现代码:functiondebounce(func,wait=500){lettimeout;//定义定时器,wait秒后定时器需要清空returnfunction(){//如果再次触发函数时超时,清除并销毁当前超时,然后用新的事件重置定时器如果(超时)clearTimeout(超时);timeout=setTimeout(function(){func();clearTimeout(timeout)},等待);};}代码2(resolvefunctionthispointsto)我们之前的原始函数指向的地方,如果我们用我们的debounce函数包裹它,这个点也应该是正确的Object。functiondebounce(func,wait=500){让超时,上下文;返回函数(){context=this;//如果再次触发函数时超时,则清除并销毁超时,然后执行if(timeout)clearTimeout(timeout);timeout=setTimeout(function(){func.apply(context);clearTimeout(timeout);},wait);};}代码3(解决函数事件对象)JavaScript会在事件处理函数event中提供事件对象;因此,保持原函数的事件对象不变。公式1:functiondebounce(func,wait=500){lettimeout,context,args;返回函数(){context=this;args=参数;//如果再次触发函数时超时,则清除并销毁超时,然后执行if(timeout)clearTimeout(timeout);timeout=setTimeout(function(){func.apply(context,args);clearTimeout(timeout);},wait);};}公式二:functiondebounce(func,wait=500){lettimeout,context;返回函数(...args){context=this;//如果再次触发函数时超时,则清除并销毁超时,然后执行if(timeout)clearTimeout(timeout);timeout=setTimeout(function(){func.apply(context,args);clearTimeout(timeout);},wait);};}代码4(函数返回值)此时我们需要注意一个问题,就是我们在执行原函数的时候可能会有返回值,我们需要处理debounce函数,必须末尾有相同的返回值这里所做的处理是将func.apply(context,args)单独取出来,输出原函数的结果。functiondebounce(func,wait=500){让超时,上下文,结果;functionshowResult(e1,e2){结果=func.apply(e1,e2);//绑定e1和e2时输出结果returnresult;}返回函数(...args){context=this;//如果再次触发函数时超时,则清除并销毁超时,然后执行if(timeout)clearTimeout(timeout);//这里不是原代码立即执行timeout=setTimeout(function(){showResult(context,args);//将this和arguments代入函数clearTimeout(timeout);},wait);};}代码五(立即执行)因为原理,每次触发后需要等待wait秒才能执行。但是在某些场景下,比如点击按钮后调用接口,整个时间会比较长。这时候需要定义immediate,点击按钮,调用接口立即执行,wait秒内达到防抖效果。functiondebounce(func,wait=500,immediate=false){让超时,上下文,结果,callNow;functionshowResult(e1,e2){结果=func.apply(e1,e2);//绑定e1,e2同时输出结果returnresult;}返回函数(...args){context=this;//如果再次触发函数时超时,则清除并销毁超时,然后执行if(timeout)clearTimeout(timeout);if(immediate){//这里是立即执行的判断代码callNow=!timeout;//timeout初始定义为undefined,如果没有设置timer,!timeout返回true;否则返回falsetimeout=setTimeout(function(){timeout=null;//这里定时器结束,让timeout为null,然后上一步!timeout仍然返回true;},wait);如果(callNow)showResult(上下文,args);//刚刚进入timeout=undefined并且,当等待时间结束时,timeout=null,这两种情况都会立即执行该函数}else{//这里是原始代码,没有立即执行timeout=setTimeout(function(){showResult(context,args);//将此参数代入函数clearTimeout(timeout);},等待);}};}代码6(Cancel)添加取消防抖的方法:只需要定义cancel方法,去掉定时器,并将初始变量全部设置为undefinedfunctiondebounce(func,wait=500,immediate=false){让超时,上下文,结果,callNow;functionshowResult(e1,e2){结果=func.apply(e1,e2);//绑定e1,e2同时输出结果returnresult;}constdebounced=function(...args){context=this;//如果再次触发函数时已经超时,则清除并销毁超时,并执行if(timeout)clearTimeout(timeout);if(immediate){//这里是立即执行的判断代码callNow=!timeout;//timeout初始定义为undefined,如果没有设置timer,!timeout返回true;否则返回falsetimeout=setTimeout(function(){timeout=null;//这里定时器结束,让timeout为null,然后上一步!timeout仍然返回true;},wait);如果(callNow)showResult(上下文,args);//只要输入timeout=undefined等待时间结束timeout=null,两种情况都会立即执行该函数}else{//这里是原始代码,没有立即执行timeout=setTimeout(function(){showResult(context,args);//将this和arguments代入函数清除超时(超时);},等待);}};debounced.cancel=function(){//移除定时器,if(timeout!==undefined){clearTimeout(timeout);}//将所有初始变量设置为未定义timeout=context=result=callNow=undefined;};returndebounced;}演示地址可以去Github仓库查看演示代码。向大师学习系列主要是了解日常生活中的每个进阶知识点,所以跟着大师深入理解JavaScript的语言艺术,后续会持续更新,希望大家不要吝啬你的赞美。??感谢您的支持!!!??如有错误或不准确的地方,请务必指正,万分感谢!!!??如果你喜欢或启发了什么,欢迎star!!!参考JavaScript专题:Followunderscoretolearnanti-shakeunderscore.js深入浅出讲解防抖功能