原博客地址,歡迎star前端
函數防抖和函數節流:優化高頻率執行js代碼的一種手段,js中的一些事件如瀏覽器的resize、scroll,鼠標的mousemove、mouseover,input輸入框的keypress等事件在觸發時,會不斷地調用綁定在事件上的回調函數,極大地浪費資源,下降前端性能。爲了優化體驗,須要對這類事件進行調用次數的限制。git
在事件被觸發n秒後再執行回調,若是在這n秒內又被觸發,則從新計時。
根據函數防抖思路設計出初版的最簡單的防抖代碼:github
var timer; // 維護同一個timer function debounce(fn, delay) { clearTimeout(timer); timer = setTimeout(function(){ fn(); }, delay); }
用onmousemove測試一下防抖函數:瀏覽器
// test function testDebounce() { console.log('test'); } document.onmousemove = () => { debounce(testDebounce, 1000); }
上面例子中的debounce就是防抖函數,在document中鼠標移動的時候,會在onmousemove最後觸發的1s後執行回調函數testDebounce;若是咱們一直在瀏覽器中移動鼠標(好比10s),會發現會在10 + 1s後纔會執行testDebounce函數(由於clearTimeout(timer)),這個就是函數防抖。閉包
在上面的代碼中,會出現一個問題,var timer只能在setTimeout的父級做用域中,這樣纔是同一個timer,而且爲了方便防抖函數的調用和回調函數fn的傳參問題,咱們應該用閉包來解決這些問題。app
優化後的代碼:frontend
function debounce(fn, delay) { var timer; // 維護一個 timer return function () { var _this = this; // 取debounce執行做用域的this var args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function () { fn.apply(_this, args); // 用apply指向調用debounce的對象,至關於_this.fn(args); }, delay); }; }
測試用例:前端性能
// test function testDebounce(e, content) { console.log(e, content); } var testDebounceFn = debounce(testDebounce, 1000); // 防抖函數 document.onmousemove = function (e) { testDebounceFn(e, 'debounce'); // 給防抖函數傳參 }
使用閉包後,解決傳參和封裝防抖函數的問題,這樣就能夠在其餘地方隨便將須要防抖的函數傳入debounce了。函數
每隔一段時間,只執行一次函數。
請仔細看清和防抖函數的代碼差別post
function throttle(fn, delay) { var timer; return function () { var _this = this; var args = arguments; if (timer) { return; } timer = setTimeout(function () { fn.apply(_this, args); timer = null; // 在delay後執行完fn以後清空timer,此時timer爲假,throttle觸發能夠進入計時器 }, delay) } }
測試用例:
function testThrottle(e, content) { console.log(e, content); } var testThrottleFn = throttle(testThrottle, 1000); // 節流函數 document.onmousemove = function (e) { testThrottleFn(e, 'throttle'); // 給節流函數傳參 }
上面例子中,若是咱們一直在瀏覽器中移動鼠標(好比10s),則在這10s內會每隔1s執行一次testThrottle,這就是函數節流。
函數節流的目的,是爲了限制函數一段時間內只能執行一次。所以,定時器實現節流函數經過使用定時任務,延時方法執行。在延時的時間內,方法若被觸發,則直接退出方法。從而,實現函數一段時間內只執行一次。
根據函數節流的原理,咱們也能夠不依賴 setTimeout實現函數節流。
function throttle(fn, delay) { var previous = 0; // 使用閉包返回一個函數而且用到閉包函數外面的變量previous return function() { var _this = this; var args = arguments; var now = new Date(); if(now - previous > delay) { fn.apply(_this, args); previous = now; } } } // test function testThrottle(e, content) { console.log(e, content); } var testThrottleFn = throttle(testThrottle, 1000); // 節流函數 document.onmousemove = function (e) { testThrottleFn(e, 'throttle'); // 給節流函數傳參 }
其實現原理,經過比對上一次執行時間與本次執行時間的時間差與間隔時間的大小關係,來判斷是否執行函數。若時間差大於間隔時間,則馬上執行一次函數。並更新上一次執行時間。
相同點:
不一樣點:
連續的事件,只需觸發一次回調的場景有:
間隔一段時間執行一次回調的場景有:
參考資料:
淺析函數防抖與函數節流
JavaScript專題系列-防抖和節流
7分鐘理解JS的節流、防抖及使用場景
防抖、節流
可能這些參考資料中有某些錯誤,可是表示感謝,博客中有些內容用了裏面的資料。