在《JavaScript高级程序设计》一书有介绍函数节流,里面封装了这样一个函数节流函数:闭包
function throttle(method, context) { clearTimeout(methor.tId); method.tId = setTimeout(function(){ method.call(context); }, 100); }
它把定时器ID存为函数的一个属性。而调用的时候就直接写app
window.onresize = function(){ throttle(myFunc); }
impress用的是另外一个封装函数:函数
var throttle = function(fn, delay){ var timer = null; return function(){ var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function(){ fn.apply(context, args); }, delay); }; };
它使用闭包的方法造成一个私有的做用域来存放定时器变量timer。而调用方法为this
window.onresize = throttle(myFunc, 100);
两种方法各有优劣,前一个封装函数的优点在把上下文变量当作函数参数,直接能够定制执行函数的this变量;后一个函数优点在于把延迟时间当作变量(固然,前一个函数很容易作这个拓展),并且我的以为使用闭包代码结构会更优,且易于拓展定制其余私有变量,缺点就是虽然使用apply把调用throttle时的this上下文传给执行函数,但毕竟不够灵活。设计
上面介绍的函数节流,它这个频率就不是50ms之类的,它就是无穷大,只要你能不间断resize,刷个几年它也一次都不执行处理函数。咱们能够对上面的节流函数作拓展:code
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(!t_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); } }; };
在这个拓展后的节流函数升级版,咱们能够设置第三个参数,即必然触发执行的时间间隔。若是用下面的方法调用ip
window.onresize = throttleV2(myFunc, 50, 100);
则意味着,50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次。原理也很简单,打时间tag,一开始记录第一次调用的时间戳,而后每次调用函数都去拿最新的时间跟记录时间比,超出给定的时间就执行一次,更新记录时间。作用域