在《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,一開始記錄第一次調用的時間戳,而後每次調用函數都去拿最新的時間跟記錄時間比,超出給定的時間就執行一次,更新記錄時間。作用域