背景
防抖函數在各個互聯網大廠的面試中,出現的頻率是非常高的,本人在面試某鵝廠的時候也正好遇見過。
那么何為防抖呢?
所謂防抖,就是指觸發事件后在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。
舉個簡單的例子,當用戶連續多次點擊某個按鈕時,而這個按鈕每點擊一次就會發送一個請求。那么當用戶連續多次點擊按鈕的時候,那豈不是也需要多次發送請求,直接產生的后果就是浪費資源,性能降低,增加服務器壓力。那么如何解決這個問題呢?如果能夠在一定時間內,只能發送一次請求就可以解決這個問題了。
防抖函數
下面就是我們平時最常見的防抖函數了,非常簡單,主要使用了setTimeout定時器,以及使用閉包,用于對防抖函數debounce中的timeout參數持續訪問。
/**
* @desc 函數防抖
* @param func 函數
* @param wait 延遲執行毫秒數
* @param immediate true 表立即執行(前沿觸發),false 表非立即執行(后沿觸發)
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout是定時器ID,只有初始化狀態下第一次觸發的時候才不會執行;后續在周期內觸發db函數會清除定時器,避免在周期內初始化timeout導致事件函數被執行
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null; // 如果周期內db函數未觸發,則重新初始化timeout
}, wait)
if (callNow) func.Apply(context, args) // 初始化狀態下,立即執行事件函數
}
else {
timeout = setTimeout(function(){ // 在周期內db函數被觸發會更新定時器,延遲事件函數的執行
func.apply(context, args)
}, wait);
}
}
}
使用場景
防抖函數多使用于如下的一些頻繁觸發的事件:
- 輸入框的 keyup / keydown
- 調整窗口大小的 resize
- 頁面滾動的 scroll
- 鼠標滑動的 mousedown / mousemove