什么是防抖 (debounce)? 如何实践防抖 (debounce) 函式?
2022年12月11日
💎 加入 E+ 成長計畫 與超過 500+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源
防抖(debounce) 和节流(throttle) 绝对是在考手写题时最常出现的前几名,这两者都能做到优化,但使用情境不太相同,本篇介绍防抖函式,在这篇文章中会继续讨论节流。
防抖 (debounce) 在做什么?
防抖 (debounce) 函式是指,将多次操作优化为,只在最后一次执行。具体来说,当一定时间内没有持续触发事件时,事件处理函式才会被执行一次,但如果在设定的时间内又一次触发了事件,就会重新开始计时。
在手写防抖 (debounce) 函式前,我们先来了解防抖的使用情境。
我们以 Google 搜寻框和搜寻建议列表为例子。画面如下,有一个搜寻框,和一个搜寻建议列表,使用者在此搜寻框输入文字后,搜寻建议列表会即时呈现结果; 搜寻框的文字只要一改变,搜寻建议列表也会即时更新结果。
这样看起来是很理想的设计吧? 但首先要去解决一个问题。如果使用者一直在搜寻框内书写文字,这样会一直触发 API 去更新搜寻建议列表,例如使用者想搜寻 javascript,这时 API 也及时触发,所以此 API 会被触发 10 次,而且前 9 次不会是使用这想要的结果。
为了提升使用者体验以及优化程式吗,这一段功能我们就可以透过防抖(debounce) 来优化。
防抖函式会接受两个参数
- 延迟的时间 (ms)
- 要执行的函式
以上面搜寻框的例子来说,我们透过防抖就可以完成:当使用者停止在搜寻框内打入文字超过一定的时间,此时才会去执行触发 API 的函式。
手写防抖 (debounce) 函式
我们先直接看代码,看看你能了解多少。有不懂的地方也不担心,下面会透过注解,一行行解释:
function debounce(fn, delay = 500) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}
代码注解版本和实际应用
// debounce function 接受两个参数
// 一是:要执行的 function
// 二是:要延迟的豪秒数,这边预设 500 毫秒
function debounce(fn, delay = 500) {
let timer;
// debounce function 最终会回传一个 function
return (...args) => {
// 每一次 debounce function 被触发时,会先清除之前的 timer,避免触发先前的 fn 函式
// 因此只要在 delay 时间内触发 debounce function,就会一直清除先前的 timer,避免 fn 一直被执行
clearTimeout(timer);
// 清除之后,再重新计时
// 当 delay 时间到时,执行 fn
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}
// updateDebounceText 会在延迟 500 ms 后执行 console.log('call api get search result')
const updateDebounceText = debounce((text) => {
console.log("call api get search result");
}, 500);
// 搜寻框监听 input 事件,当 input 改变时
// 触发 updateDebounceText 函式
searchInput.addEventListener("input", (e) => {
updateDebounceText(e.target.value);
});