背景:在前端开发中,有时会为页面绑定resize事件,或为一个页面元素拖拽事件(其核心就是绑定mousemove)在一个正常操作中也有可能在一个短时间内触发非常多次事件绑定程序,而DOM操作是很消耗性能的,如果为这些事件绑定一些操作DOM节点的操作的话就会引发大量的计算,在用户看来页面可能就一时间没有响应,这个页面就变卡变慢了,甚至在IE下,如果绑定的resize事件进行较多DOM操作,其高频率可能直接就使得浏览器崩溃。
函数节流简单讲就是让一个函数无法在很短的时间间隔内连续调用,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。
函数节流原理:用定时器,当触发一个事件时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行。
优缺点:
《JavaScript高级程序设计》中介绍的函数节流
function throttle(method,context){ clearTimeout(method,tId); method.tId=setTimeout(function(){ method.call(context); },100); } //调用 window.onresize=function(){ throttle(myFunc); } //法二: var throttle=function(fn,delay){ var timer=null; return function(){ var context=this,args=arguments; clearTimeout(timer); timer=setTimeout(function(){ fn.apply(context,args);//context调用fn的方法,指针指向了fn },delay); } } //调用 window.onresize=throttle(myFunc,100);
函数节流让一个函数只有在你不断触发后停下来歇会才开始执行,中间你操作得太快它直接无视你。这样做就有点太绝了,resize一般还好,但假如写一个拖拽元素位置的程序,然后直接使用函数节流,会发现你拖动时元素是不动的,你拖完了它直接闪到终点去,所以进行优化:
var throttleV2=function(fn,delay,mustRunDelay){ var timer=null; var t_start; return function(){ var context=this,args=arguments,t_curr=+new Date(); clearTimeout(timer); if(!s_start){ t_start=t_curr; }if(t_curr-t_start>=mustRunDelay){ fn.apply(context,args); t_start=t_curr; }else{ timer=setTimeout(function(){ fn.apply(context,args); },delay); } } } window.onresize=throttleV2(myFunc,50,100);
解析:50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次。
1.具有节流效果的tab切换案例:
var timer=null; function tab(obj){ var target = document.getElementById(obj); var spans = target.getElementsByTagName("span"); var lis = target.getElementsByTagName("li"); for(var i=0;i<spans.length;i++) { spans[i].onmouseover = function(num){ return function(){ clearTimeout(timer); timer=setTimeout(function(){ for(var j=0; j<spans.length;j++) { spans[j].className = ""; lis[j].className = ""; } spans[num].className = "current"; lis[num].className = "show"; },300); } }(i); spans[i].onmouseout=function(){ clearTimeout(timer); } } } tab("one");
2.屏幕缩放节流案例:
<body> <div id="demo"></div> </body> </html> <script> var demo=document.getElementById("demo"); var num=0; window.onresize=throll(function(){ demo.innerHTML=window.innerWidth || document.documentElement.clientWidth; num++; alert(num); },300); function throll(fn,delay){ var timer=null; return function(){ clearTimeout(timer); timer=setTimeout(fn,delay); } } </script>