javascript中的函數大多數狀況下都是由用戶主動調用觸發的, 除非是函數自己的實現不合理, 不然通常不會遇到跟性能相關的問題,但在少數狀況下, 函數的觸發不是由用戶直接控制的. 在這些場景下, 函數可能被很是頻繁調用, 而形成大的性能問題.javascript
window.onresize事件
mousemove事件
scroll滾動事件
共同的特徵:高頻觸發事件函數, 若事件函數裏附帶DOM相關操做, 會形成很是大的性能消耗.java
將即將被執行的函數使用setTimeout延遲一段時間執行, 若是該次延遲執行尚未完成, 則忽略接下來調用該函數的請求.設計模式
underscore.js的函數節流定義: _.throttle(fn, wait, [options]);app
_.throttle接收三個參數, 第一次執行默認馬上執行一次fn @params fn: 須要進行函數節流的函數; @params wait: 函數執行的時間間隔, 單位是毫秒. @params options: options有兩個選項, 分別是: {leading: false}: 第一次調用不執行fn {trailing: false}: 禁止最後一次延遲的調用 _.throttle = function(fn, wait, options) { var context, args, result, timeout = null, previous = 0; if(!options) { options = {}; } var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = fn.apply(context, args); if(!timeout) { context = args = null; } }; return function() { var now = _.now(); if(!previous && options.leading === false) { previous = now; } var remaining = wait - (now - previous); context = this; args = arguments; if(remaining <= 0 || remaining > wait) { if(timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = fn.apply(context, args); if(!timeout) { context = args = null; } else if(!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; } }; }; // demo: $(window).scroll(_.throttle(function() { //相關處理 }, 500));
《javascript設計模式與開發實戰》中對函數節流示例:函數
throttle函數接收兩個參數 @params fn: 須要被延遲執行的函數; @params interval: 延遲執行的時間; var throttle = function(fn, interval) { var _self = fn, // 保存須要被延遲執行的函數引用 timer, // 計時器 firstTime = true; // 是否第一次調用 return function() { var args = arguments, _this = this; if(firstTime) { // 若是是第一次調用, 不須要延遲執行 _self.apply(_this, args); return firstTime = false; } if(timer) { // 若是定時器還在, 說明前一次延遲執行還未完成 return false; } timer = setTimeout(function() { clearTimeout(timer); timer = null; _self.apply(_this, args); }, interval || 500); }; }; // demo: window.onresize = throttle(function() { console.log(1); }, 500);