前端面試手寫練習 - debounce
- 文章發表於
問題
debounce 與 throttle 都是在前端開發中相當常見的一種優化手段,而 debounce 的概念就是當事件被觸發後,會延遲一段時間再執行,如果在這段時間內又被觸發,則會重新計算延遲時間。
debounce(func, [(wait = 0)])
- func:要防抖動的事件函式
- wait:延遲時間,單位為毫秒
示意圖
原始事件流 (每 ─ 代表 1s):─ A ─ B ─ C ─ ─ D ─ ─ ─ ─ ─ ─ E ─ ─ F ─ G ─ ─ ─加入 throttle (wait: 3s) 之後:─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ D ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ G
可以看到加入 debounce 之後,只有事件 D
與 G
被執行。
範例
實務上最經典的例子就是透過 debounce 來優化搜尋功能,當使用者輸入關鍵字時,並不會立即發送請求,而是等待一段時間,再發送下一個請求。
可以看到輸入關鍵字時,「累積請求發送次數」只有在停止輸入的一段時間後才會增加。亦即加入 debounce 後減少了對後端請求的發送次數,減緩了伺服器的負擔。
相反的,如果把在 keyup 時的 debounce 函式移除,則會在每次輸入時都會看到「累積請求發送次數」的次數增加。
練習區
在了解問題後,可以嘗試先寫下您的思路,再到下方的練習區域實際寫出程式碼。
筆者思路
- 這與 throttle 的實作方式非常相近,但較於 throttle 是在 timeout 結束時將開關再次打開, debounce 則是在 timeout 結束時呼叫
func
並將timer
設為null
。 - 照著這個思路,我們可以先宣告一個
timer
變數,並在 debounce 函式中返回一個新的函式。 - 在這個新函式中,我們會先檢查
timer
是否存在,如果存在則清除計時器。 - 接著設定一個新的計時器,並在時間到時執行
func
,並將timer
設為null
。
筆者解答
function debounce(func, wait = 0) {let timer = nullreturn function (...args) {if (timer) {clearTimeout(timer)}timer = setTimeout(() => {timer = nullfunc.apply(this, args)}, wait)}}