js 函數節流 jQuery throttle/debounce


在《JavaScript高級程序設計》一書有介紹函數節流,里面封裝了這樣一個函數節流函數:

 function throttle(method, context) {
     clearTimeout(methor.tId);
     method.tId = setTimeout(function(){
         method.call(context);
     }, 100);
 }

它把定時器ID存為函數的一個屬性。而調用的時候就直接寫

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。而調用方法為

window.onresize = throttle(myFunc, 100);

兩種方法各有優劣,前一個封裝函數的優勢在把上下文變量當做函數參數,直接可以定制執行函數的this變量;后一個函數優勢在於把延遲時間當做變量(當然,前一個函數很容易做這個拓展),而且個人覺得使用閉包代碼結構會更優,且易於拓展定制其他私有變量,缺點就是雖然使用apply把調用throttle時的this上下文傳給執行函數,但畢竟不夠靈活。

上面介紹的函數節流,它這個頻率就不是50ms之類的,它就是無窮大,只要你能不間斷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(!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);
 		}
 	};
 };

在這個拓展后的節流函數升級版,我們可以設置第三個參數,即必然觸發執行的時間間隔。如果用下面的方法調用

window.onresize = throttleV2(myFunc, 50, 100);

則意味着,50ms的間隔內連續觸發的調用,后一個調用會把前一個調用的等待處理掉,但每隔100ms至少執行一次。原理也很簡單,打時間tag,一開始記錄第一次調用的時間戳,然后每次調用函數都去拿最新的時間跟記錄時間比,超出給定的時間就執行一次,更新記錄時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM