咱們常常須要監聽滾動條滾動或者鼠標的移動,但瀏覽器觸發這類事件的頻率很是高,可能在10幾毫秒就觸發一次,若是咱們處理事件的函數須要操做大範圍的DOM,這對於瀏覽器的性能是個考驗,可能像chrome瀏覽器這樣優秀的瀏覽器會好一點,但放到老版本的IE下,就可能發生卡頓現象。有的時候,咱們只須要處理函數執行一次,好比文本輸入驗證,執行屢次處理函數反而沒有必要。javascript
因此咱們得想個辦法,減小DOM操做的頻度,也就是說稀釋處理函數的執行頻率,解決方法就是函數防抖和函數分流。函數防抖表示只執行一次處理函數,函數分流指下降處理函數的執行頻率,下面是具體解釋。java
函數防抖指的是屢次觸發事件後,事件處理函數只執行一次,並且是在事件觸發操做中止的時候。具體的思路就是延遲處理函數,若是設定的時間到來以前,又一次觸發了事件,就清除上一次的定時器,具體代碼實現以下。git
var obj = document.getElementById('handle'); /** * 事件觸發的操做 */ function myFun() { console.log('throttleV1'); } /** * 不封裝的方法 */ obj.onmousemove = function () { clearTimeout(myFun.timer); myFun.timer = setTimeout(myFun,50); }
這裏有一個保存timer的技巧,若是不保存timer,那麼執行完事件處理函數後,timer將被銷燬,咱們也就沒法再清楚定時器了,因此須要保存這個變量,即便它所在的函數做用域對應的函數已經執行完了。這裏用到的技巧是把timer設置爲外部函數的屬性,這樣就不會被銷燬了。
咱們還能夠對這個方法進行封裝。github
/** * 封裝的方法之幫頂函數 * @param method * @param delay * @param context */ function debounce(method, delay, context) { clearTimeout(method.timer); method.timer = setTimeout(function () { method.call(context); },delay); } obj.onmousemove = function () { debounce(myFun,50); };
這裏涉及到了保存timer的技巧,總共有兩個方法。web
/** * 封裝的方法之閉包 * 閉包 若是想讓一個函數執行完後,函數內的某個變量(timer)仍舊保留,就可使用閉包 * 把要保存的變量在父做用域聲明,其餘的語句放到子做用域裏,而且做爲一個function返回 * 因此閉包能夠理解爲分離變量 */ function debounce(method,delay) { var timer=null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { method.apply(context,args); },delay); } } obj.onmousemove = debounce(myFun,50);
函數分流的思想就是計時,上面的代碼是隻有在操做結束後才執行,只須要在上面的代碼上加一個計時判斷,若是超過了設定的時間,就執行一次處理函數,就達到了分流的效果。chrome
/** * 函數節流throttle * @param 事件觸發的操做 * @param 延遲執行函數的時間 * @param 超過多長時間必須執行一次函數 * @returns {Function} */ function throttle(method, delay, mustRunDelay) { var timer = null, args = arguments; var start = 0, now = 0; return function () { var context = this; now= Date.now(); if(!start){ start = now; } if(now - start >= mustRunDelay){ method.apply(context, args); start = Date.now(); }else { clearTimeout(timer); timer = setTimeout(function () { method.apply(context, args); }, delay); } } } obj.onmousemove = throttle(myFun, 50, 500);
函數防抖和函數分流的思想都是經過定時器控制函數的執行頻率。瀏覽器
http://www.alloyteam.com/2012/11/javascript-throttle/
http://web.jobbole.com/88306/
https://github.com/hanzichi/underscore-analysis/issues/21
https://github.com/hanzichi/underscore-analysis/issues/22閉包