浏覽器中某些計算和處理要比其他的昂貴的多。例如,DOM操作比起非DOM交互需要更多的內存和CPU時間。連續嘗試進行過多的DOM相關操作可能會導致 浏覽器掛起,有時候甚至會崩潰。尤其在IE中使用onresize事件處理程序的時候容易發生,當調整浏覽器大小的時候,該事件連續觸發。在 onresize事件處理程序內部如果嘗試進行DOM操作,其高頻率的更改可能會讓浏覽器崩潰。
函數節流背後的基本思想是,某些代碼不可以在沒有間斷的情況連續重復執行。第一次調用函數,創建一個定時器,在指定的時間間隔之後運行代碼。當第二次調用 該函數時,它會清除前一次的定時器並設置另一個。如果前一個定時器已經執行過了,這個操作就沒有任何意義。然而,如果前一個定時器尚未執行,其實就是將其 替換為一個新的定時器。目的是只有在執行函數的請求停止了一段時間之後才執行。
function throttle ( method , context ){ clearTimeout ( method.tId ); method.tId = setTimeout ( function () { method.call ( context ); } , 100); }
應用舉例:
假設有一個<div/>元素需要保持它的高度始終等同於寬度,可作如下編碼:
function resizeDiv(){ var div = document.getElementById("mydiv"); div.style.height = div.offsetWidth + "px"; } window.onresize = function(){ throttle(resizeDiv); }
這裡,調整大小的功能被放入了一個叫做resizeDiv的單獨函數中,然後onresize事件處理程序調用throttle()並傳入 resizeDiv函數,而不是直接調用resizeDiv()。多數情況下,用戶是感覺不到變化的,雖然給浏覽器節省的計算可能非常大。
下面是其他網友的補充
今天主要寫寫我們平時工作中需要的函數節流。可能有的朋友對函數節流沒有意識。其實,在工作中,很多場景都需要我們進行js的節流。最常見的是屏幕伸縮resize,以及touchmove或者scroll等事件的時候。大家不知道有沒有看我之前寫的文章!jquery判斷頁面滾動條上滾下滾,touchmove的滑動方向,大家在使用這些例子的時候,會發現頁面不停的觸發touchmove或者scroll因為這裡沒有關系到頁面的重繪,因此,我在這裡沒有使用javascript函數節流。但是,當我們使用window.onresize的時候,也會不停的觸發resize事件!這裡就會關系到頁面的重新繪制問題了。因此,在window的resize的時候,我們推薦大家使用函數節流的方式!
javascript函數節流簡介
假如你對我上面一大坨文字感到頭大,沒關系,我在這裡簡單舉例說明一下函數節流吧!例如當我們使用
$(window).resize(function(){ console.log("haorooms window resize"); })
會發現:
這裡會輸出好多次。我們簡單的縮小一下窗口,就會不停的觸發!
這樣在div很多的時候,頁面不停重繪,要是遇到版本比較低的IE等,很可能會出現浏覽器崩潰的現象!為了避免這種情況,我們可以用函數節流的方式。基本的思想是:第一次調用函數的時候,我們創建一個定時器,在指定時間間隔之後運行代碼,第二次調用的時候,會清楚前一個定時器,並重新設置一個。如果前一個定時器已經執行過了,那麼這個操作就沒有有意了,如果定時器尚未執行,就會將其替換為一個新的定時器。目的是在執行函數停止了一段時間之後再執行。
用對象的方式可以如下寫:
var haoroomstest={ timeoutId:null, performProcessing:function(){ console.log("resize"); }, process:function(){ clearTimeout(this.timeoutId); var that=this; this.timeoutId=setTimeout(function(){ that.performProcessing(); },500) } }
這樣之後,我們再用:
$(window).resize(function(){ haoroomstest.process(); })
這樣就會減少請求,減少dom重繪,達到節流的目的!
函數節流其他方式
除了我們運用對象的方式,網上及資料中也介紹了關於函數節流的其他方法和方式,我下面簡單介紹幾種!
函數方式一
function throttle(method,context){ clearTimeout(method.tId); method.tId=setTimeout(function(){ method.call(context); },100); }
我們如下使用
function resizeDIv(){ console.log("haorooms") } $(window).resize(function(){ throttle(resizeDIv) })
和上面對象實現了同樣的效果!
函數方式二
網上還有一種比較流行的節流方式,我在這裡寫一下!
function throttle(method,delay){ var timer=null; return function(){ var context=this, args=arguments; clearTimeout(timer); timer=setTimeout(function(){ method.apply(context,args); },delay); } }
然後可以這麼寫:
function resizeDIv(){ console.log("haorooms") } window.onresize=throttle(resizeDIv,500);
新需求
我們在做模糊搜索智能聯想提示的時候,會在input上面綁定keyup事件。但是我又不想觸發的那麼頻繁,用上面的方式就會有問題。因此,在上面的函數基礎上稍加改動,如下:
function throttle(method,delay,duration){ var timer=null, begin=new Date(); return function(){ var context=this, args=arguments, current=new Date();; clearTimeout(timer); if(current-begin>=duration){ method.apply(context,args); begin=current; }else{ timer=setTimeout(function(){ method.apply(context,args); },delay); } } }
這樣觸發就不會有之前那麼頻繁了!