講真 哪一個是節流throttle,哪一個是去抖debounce,無所謂啦。。。javascript
硬要區分的話,我以爲是這種:css
http://blog.peterwf.com/2015/11/17/debounce-throttle/前端
參考:https://css-tricks.com/the-difference-between-throttling-and-debouncing/java
或者就不要區分了,就都是節流。這個講得最好:sublime-text
http://www.alloyteam.com/2012/11/javascript-throttle/#prettyPhoto瀏覽器
function throttle(fn,delay){ var timer = null; console.log(this);//window return function (){//使用閉包,保證了全局的timer var context = this, args = arguments; // console.log(this);//btn clearTimeout(timer); timer = setTimeout(function (){ fn.apply(context,args);//context保證了fn裏的this的正確性:btn },delay); }; }; function fn(){ console.log(this); console.log("執行"); } $("#btn").on("click",throttle(fn, 1000)); //click以前就執行了throttle。執行結果給了click // $("#btn").on("click",fn);
介紹前,先說下背景。在前端開發中,有時會爲頁面綁定resize事件,或者爲一個頁面元素綁定拖拽事件(其核心就是綁定mousemove),這種事件有一個特色,就是用戶沒必要特意搗亂,他在一個正常的操做中,都有可能在一個短的時間內觸發很是屢次事件綁定程序。而你們知道,DOM操做時很消耗性能的,這個時候,若是你爲這些事件綁定一些操做DOM節點的操做的話,那就會引起大量的計算,在用戶看來,頁面可能就一時間沒有響應,這個頁面一會兒變卡了變慢了。甚至在IE下,若是你綁定的resize事件進行較多DOM操做,其高頻率可能直接就使得瀏覽器崩潰。閉包
怎麼解決?函數節流就是一種辦法。話說第一次接觸函數節流(throttle),仍是在看impress源代碼的時候,impress在播放的時候,若是窗口大小發生改變(resize),它會對總體進行縮放(scale),使得每一幀都完整顯示在屏幕上:app
稍微留心,你會發現,當你改變窗體大小的時候,無論你怎麼拉,怎麼拽,都沒有馬上生效,而是在你改變完大小後的一下子,它的內容才進行縮放適應。看了源代碼,它用的就是函數節流的方法。ide
函數節流,簡單地講,就是讓一個函數沒法在很短的時間間隔內連續調用,只有當上一次函數執行後過了你規定的時間間隔,才能進行下一次該函數的調用。以impress上面的例子講,就是讓縮放內容的操做在你不斷改變窗口大小的時候不會執行,只有你停下來一下子,纔會開始執行。函數
函數節流的原理挺簡單的,估計你們都想到了,那就是定時器。當我觸發一個時間時,先setTimout讓這個事件延遲一會再執行,若是在這個時間間隔內又觸發了事件,那咱們就clear掉原來的定時器,再setTimeout一個新的定時器延遲一會執行,就這樣。
明白了原理,那就能夠在代碼裏用上了,但每次都要手動去新建清除定時器畢竟麻煩,因而須要封裝。在《JavaScript高級程序設計》一書有介紹函數節流,裏面封裝了這樣一個函數節流函數:
1
2
3
4
5
6
|
function throttle(method, context) {
clearTimeout(methor.tId);
method.tId = setTimeout(function(){
method.call(context);
}, 100);
}
|
它把定時器ID存爲函數的一個屬性(= =我的的世界觀不喜歡這種寫法)。而調用的時候就直接寫
1
2
3
|
window.onresize = function(){
throttle(myFunc);
}
|
這樣兩次函數調用之間至少間隔100ms。
而impress用的是另外一個封裝函數:
1
2
3
4
5
6
7
8
9
10
|
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。而調用方法爲
1
|
window.onresize = throttle(myFunc, 100);
|
兩種方法各有優劣,前一個封裝函數的優點在把上下文變量當作函數參數,直接能夠定製執行函數的this變量;後一個函數優點在於把延遲時間當作變量(固然,前一個函數很容易作這個拓展),並且我的以爲使用閉包代碼結構會更優,且易於拓展定製其餘私有變量,缺點就是雖然使用apply把調用throttle時的this上下文傳給執行函數,但畢竟不夠靈活。
接下來就討論怎麼更好地封裝?這多沒意思啊,接下來討論下怎樣拓展深化函數節流。
真是棒!
http://www.alloyteam.com/2012/11/javascript-throttle/#prettyPhoto