如何解决js函数防抖、节流出现的问题
React中使用防抖函数和节流函数
在React事件调用时,React传递给事件处理程序是一个合成事件对象的实例。SyntheticEvent对象是通过合并得到的。这意味着在事件回调被调用后,SyntheticEvent对象将被重用并且所有属性都将被取消。这是出于性能原因。因此,您无法以异步方式访问该事件。React合成事件官方文档
所以在用防抖或节流函数封装时,异步方式访问事件对象出现问题。解决的方法如下:
方法一:调用合成事件对象的persist()方法event.persist&&event.persist()//保留对事件的引用
方法二:深拷贝事件对象constevent=e&&{...e}//深拷贝事件对象
functiondebounce(func,wait=500){ lettimeout;//定时器变量 returnfunction(event){ clearTimeout(timeout);//每次触发时先清除上一次的定时器,然后重新计时 event.persist&&event.persist()//保留对事件的引用 //constevent=e&&{...e}//深拷贝事件对象 timeout=setTimeout(()=>{ func(event) },wait);//指定xxms后触发真正想进行的操作handler }; }
防抖debounce
防抖Debounce多次触发,只在最后一次触发时,执行目标函数。
函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算。
应用场景
(1)通过监听某些事件完成对应的需求,比如:
通过监听scroll事件,检测滚动位置,根据滚动位置显示返回顶部按钮
通过监听resize事件,对某些自适应页面调整DOM的渲染(通过CSS实现的自适应不再此范围内)
通过监听keyup事件,监听文字输入并调用接口进行模糊匹配
(2)其他场景
表单组件输入内容验证
防止多次点击导致表单多次提交
简单实现
functiondebounce(fn,wait){ lett return()=>{ letcontext=this letargs=arguments if(t)clearTimeout(t) t=setTimeout(()=>{ fn.apply(context,args) },wait) } }
完整实现
functiondebounce(func,wait,immediate){ lettime; letdebounced=function(){ letcontext=this; if(time)clearTimeout(time); if(immediate){ letcallNow=!time; if(callNow)func.apply(context,arguments); time=setTimeout( ()=>{time=null}//见注解 ,wait) }else{ time=setTimeout( ()=>{func.apply(context,arguments)} ,wait) } }; debounced.cancel=function(){ clearTimeout(time); time=null }; returndebounced } //underscore.jsdebounce // //Returnsafunction,that,aslongasitcontinuestobeinvoked,willnot //betriggered.Thefunctionwillbecalledafteritstopsbeingcalledfor //Nmilliseconds.If`immediate`ispassed,triggerthefunctiononthe //leadingedge,insteadofthetrailing. _.debounce=function(func,wait,immediate){ vartimeout,args,context,timestamp,result; //处理时间 varlater=function(){ varlast=_.now()-timestamp; if(last=0){ timeout=setTimeout(later,wait-last);//10ms6ms4ms }else{ timeout=null; if(!immediate){ result=func.apply(context,args); if(!timeout)context=args=null; } } };
react中调用方法
this.handleGetCustomerNameList=debounce(this.handleGetCustomerNameList.bind(this),500);
节流throttle
节流:函数间隔一段时间后才能再触发,避免某些函数触发频率过高,比如滚动条滚动事件触发的函数。
###简单实现 functionthrottle(fn,wait,mustRun){ letstart=newDate() lettimeout return()=>{ //在返回的函数内部保留上下文和参数 letcontext=this letargs=arguments letcurrent=newDate() clearTimeout(timeout) letremaining=current-start //达到了指定触发时间,触发该函数 if(remaining>mustRun){ fn.apply(context,args) start=current }else{ //否则wait时间后触发,闭包保留一个timeout实例 timeout=setTimeout(fn,wait); } } }
完整实现
functionthrottle(func,wait,options){ lettime,context,args,result; letprevious=0; if(!options)options={}; letlater=function(){ previous=options.leading===false?0:newDate().getTime(); time=null; func.apply(context,args); if(!time)context=args=null; }; letthrottled=function(){ letnow=newDate().getTime(); if(!previous&&options.leading===false)previous=now; letremaining=wait-(now-previous); context=this; args=arguments; if(remaining<=0||remaining>wait){ if(time){ clearTimeout(time); time=null; } previous=now; func.apply(context,args); if(!time)context=args=null; }elseif(!time&&options.trailing!==false){ time=setTimeout(later,remaining); } }; returnthrottled; } //underscore.jsthrottle //Returnsafunction,that,wheninvoked,willonlybetriggeredatmostonce //duringagivenwindowoftime.Normally,thethrottledfunctionwillrun //asmuchasitcan,withoutevergoingmorethanonceper`wait`duration; //butifyou'dliketodisabletheexecutionontheleadingedge,pass //`{leading:false}`.Todisableexecutiononthetrailingedge,ditto. _.throttle=function(func,wait,options){ varcontext,args,result; vartimeout=null; varprevious=0; if(!options)options={}; varlater=function(){ previous=options.leading===false?0:_.now(); timeout=null; result=func.apply(context,args); if(!timeout)context=args=null; }; returnfunction(){ varnow=_.now(); if(!previous&&options.leading===false)previous=now; varremaining=wait-(now-previous); context=this; args=arguments; if(remaining<=0||remaining>wait){ if(timeout){ clearTimeout(timeout); timeout=null; } previous=now; result=func.apply(context,args); if(!timeout)context=args=null; }elseif(!timeout&&options.trailing!==false){ timeout=setTimeout(later,remaining); } returnresult; }; };
react中调用方法
this.handleGetCustomerNameList=throttle(this.handleGetCustomerNameList.bind(this),500);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。