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






