JavaScript函式節流和函式去抖知識點學習
概念
節流 (throttle) 讓一個函式不要執行的太頻繁,減少執行過快的呼叫,叫節流
去抖 (debounce) 去抖就是對於一定時間段的連續的函式呼叫,只讓其執行一次
throttle 應用場景
- DOM 元素的拖拽功能實現(mousemove)
- 射擊遊戲的 mousedown/keydown 事件(單位時間只能發射一顆子彈)
- 計算滑鼠移動的距離(mousemove)
- Canvas 模擬畫板功能(mousemove
- 搜尋聯想(keyup
- 監聽滾動事件判斷是否到頁面底部自動載入更多:給 scroll 加了 debounce 後,只有使用者停止滾動後,才會判斷是否到了頁面底部;如果是 throttle 的話,只要頁面滾動就會間隔一段時間判斷一次
debounce 應用場景
每次 resize/scroll 觸發統計事件
文字輸入的驗證(連續輸入文字後傳送 AJAX 請求進行驗證,驗證一次就好)
函式去抖的實現
我們以scroll事件為例,探究如何是實現滾動一次視窗列印一個hello world 字串。 如果不對其節流或者去抖:
window.onscroll = function () {
console.log('hello world');
}
這樣每滾動一次,實際上會列印多個 hello world。 函式去抖背後的思路是指,某些程式碼不可能在沒有間斷的情況下連續執行。建立一個定時器,在指定的時間間隔之後執行程式碼。當第二次呼叫該函式時,它會清除前一次的定時器並設定另一個。如果前一個定時器已經執行過了,這個操作就沒有任何意義。然而,如果前一個定時器尚未執行,其實就是將其替換為一個新的定時器。目的是隻有在執行函式的請求停止了一段時間之後才執行。
《高程三》給出了最簡潔最經典的去抖程式碼,如下:
function debounce(method, context) {
clearTimeout(method.tId);
method.tId = setTimeout(function() {
method.call(context);
}, 1000);
}
function print() {
console.log('hello world');
}
window.onscroll = function() {
debounce(print);
};
前端全棧學習交流圈:866109386,面向1-3經驗年前端開發人員,幫助突破技術瓶頸,提升思維能力,群內有大量PDF可供自取,更有乾貨實戰專案視訊進群免費領取。
再做一些改動
function debounce(delay, action) {
var tId;
return function () {
var context = this;
var arg = arguments;
if (tId) clearTimeout(tId);
tId = setTimeout(function () {
action.apply(context, arg);
}, delay);
}
}
window.onscroll = debounce(1000, print);
函式節流的實現
函式節流就是讓連續執行的函式,變為固定時間段間斷地執行。 大概有兩種方式實現。
其一使用時間戳來判斷是否已經到回撥執行時間,記錄上次執行的時間戳,然後每次觸發事件時執行回撥,回撥中判斷當前時間戳距離上次執行時間戳的時間間隔是否有*s,如果是,則執行,並更新上次執行的時間戳,如此迴圈。
var throttle = function(delay, action) {
var last = 0;
return function() {
var curr = new Date();
if (curr - last > delay) {
action.apply(this, arguments);
last = curr;
}
}
}
第二種方法是使用定時器,比如,當scroll事件剛觸發時,列印一個hello world ,然後設定一個1000ms的定時器,此後每次觸發scroll事件,觸發回撥,如果已經存在定時器,則回撥不執行方法,知道定時器出發,handler被清除,然後重新設定定時器。
var throttle = function(delay, action) {
var timeout;
var later = function () {
timeout = setTimeout(function(){
clearTimeout(timeout);
// 解除引用
timeout = null;
}, delay);
};
later();
if (!timeout) {
action.apply(this, arguments);
later();
}
}
更新方法:
function throttlePro(delay, action) {
var tId;
return function () {
var context = this;
var arg = arguments;
if (tId) return;
tId = setTimeout(function () {
action.apply(context, arg);
clearTimeout(tId);
// setTimeout 返回一個整數,clearTimeout 之後,tId還是那個整數,setInterval同樣如此
tId = null;
}, delay);
}
}
最後
為了幫助大家讓學習變得輕鬆、高效,給大家免費分享一大批資料,幫助大家在成為全棧工程師,乃至架構師的路上披荊斬棘。在這裡給大家推薦一個前端全棧學習交流圈:866109386.歡迎大家進群交流討論,學習交流,共同進步。
當真正開始學習的時候難免不知道從哪入手,導致效率低下影響繼續學習的信心。
但最重要的是不知道哪些技術需要重點掌握,學習時頻繁踩坑,最終浪費大量時間,所以有有效資源還是很有必要的。