Debounce

MISC

什麼是 Debounce ?

Debounce 是一種避免事件反覆觸發的手段。假設使用者在不必要的操作下會連續觸發某種相同的事件,我們就能透過 Debounce 就能將前面幾次排除,僅執行最後一次觸發的結果。


常見應用

  • 輸入匡的自動補完:
    每當使用者輸入字元後便會要一次結果,但通常使用者輸入的都會是一串複數的字元,
    因此前幾次的觸發通常都是毫無意義的。
  • 表單驗證:
    表單驗證是一個複雜的過程,沒必要讓使用者每次敲下鍵盤就運算一次。
  • 畫面滾動”後”的運算:
    某些元素在捲軸滾動時會跑到畫面外,滾動停止後再跟上等等的行為。
  • 一些奇怪的實作:
    以前在做一些行銷企劃頁面的小遊戲,使用者會需要連續點擊畫面來計數,
    一但鬆懈一段時間就會把計數送出並歸零。

實作方式

傳入參數:

  1. func:欲執行的函式。
  2. ms:時間參數,用來判斷最後一次觸發後,間隔多久才真的執行第一參數。

原理:
利用 setTimeout 來建立延遲執行的行為,並且在每次觸發函式時先清掉上一個計時器。
至於要怎麼讓每次執行都針對同一個計時器做操作,就要透過閉包來實現。
對閉包還不熟的話可以看這篇 -> 為什麼 Leetcode 第 2667 題很重要?

// 實作
// 利用閉包先將計時器、要執行的函式、延後時間保存起來。
const debounce = (func, ms) => {
let timer;

// 等真的要執行的時候才放入函式自身需要的參數。
return (...arg) => {
// 我們的目的是只保留最後一個觸發,所以每次觸發都要移除之前的計時器。
clearTimeout(timer);

// 最後建立新的計時器,只要執行前沒有再被觸發,那這個計時器就會如期啟動函式。
timer = setTimeout(() => {
func(...arg);
}, ms);
}
}


// 使用
// 假定我們有個想觸發的函式
const clickToTriggerAlert = (alertMsg) => {
alert(alertMsg);
};

// 將其放入 debounce, 我希望他在點擊後的一秒才真正觸發。
const debouncedAlertTrigger = debounce(clickToTriggerAlert, 1000);

// 完成了,再來就看你想掛在 dom 上或怎麼操作都可以,
// 但要記得執行時仍然要傳入原本預計給 clickToTriggerAlert 的參數。

Lodash - Debounce

像這種造輪子的事情都已經有許多大師幫我們封裝好了,以 lodash 來說,不僅是原本的功能,他還多了第三參數可以調整一些細部行為,像是最大等待、觸發時機等,甚至在回傳函式中插入了 cancelflush 兩種方法,分別來取消原本的計時以及立即觸發函式。站在巨人的肩膀上真的讓一切輕鬆許多呀。

Comments