JavaScript 如何做防抖

你有没有遇到过这种情况:输入框里打几个字,就触发好几次搜索请求;滚动页面时,监听滚动事件的函数疯狂跑,直接把浏览器卡得掉帧?其实这些问题,大多是“函数触发太频繁”导致的,而JavaScript里的防抖,就是专门解决这个麻烦的小工具。

什么是防抖?用生活化例子秒懂

咱们先想个场景:你家小区门口的快递柜,快递员放快递时,不会你刚到门口就立刻开柜门,而是等你站定了、准备掏手机扫码了,柜门才弹开。这就是防抖的核心逻辑——把“多次触发的动作”合并成“最后一次触发后延迟执行”。

JavaScript 如何做防抖

对应到代码里,就是:如果用户在1秒内连续触发同一个函数,就不算数,重新计时;直到用户停止触发1秒后,才真正执行函数。比如搜索框的联想功能,用户每打一个字就触发输入事件,要是直接发请求,会给服务器添乱;用了防抖后,用户打完字停个0.5秒,才发请求,既不耽误体验,又能省资源。

手写防抖函数:拆解步骤,一看就会

咱们用最基础的代码例子,把防抖的原理拆成3步,保证你能看懂:

  • 先存定时器ID:每次触发函数,先把之前没执行的定时器清掉,相当于“取消上一次的临时动作”;
  • 重新计时:用setTimeout设置新的定时器,约定“多少毫秒后执行真正的函数”;
  • 暴露可调用的函数:把防抖后的函数返回出去,用的时候直接调它就行。

举个实际的代码片段(不用怕看不懂,都是简单逻辑):

`javascript

// 自定义防抖函数,接收要执行的函数和延迟时间

function debounce(func, delay = 500) {

let timerId; // 存定时器的ID

// 返回新函数,每次调用这个新函数就是触发防抖

return function(...args) {

// 清掉之前的定时器,相当于重置计时

clearTimeout(timerId);

// 设新定时器,delay毫秒后执行原函数,把参数传进去

timerId = setTimeout(() => func.apply(this, args), delay);

};

}

`

你看,这么一小段代码就实现了防抖。要是用它做搜索联想,只要把原来的请求函数传进去就行:

`javascript

// 原来的搜索请求函数

function search(keyword) {

console.log(搜索关键词:${keyword},发请求);

}

// 用防抖包装一下,延迟500毫秒执行

const debouncedSearch = debounce(search, 500);

// 输入框的输入事件就绑这个包装后的函数

inputElement.addEventListener('input', (e) => debouncedSearch(e.target.value));

`

现在用户打“JavaScript”,每打一个字就触发一次debouncedSearch,但每次都会清掉之前的定时器,直到用户打完最后一个字停0.5秒,才会输出“搜索关键词:JavaScript,发请求”——完美解决频繁触发的问题。

用防抖的小细节:别踩这2个坑

知道了原理,用的时候还要注意两个实用小技巧:

第一个是立即执行的防抖:有时候你需要“第一次触发就立刻执行,之后连续触发就防抖”,比如页面滚动到底部加载更多,要是等停止滚动再加载,用户会等很久。这时候只要给防抖函数加个参数immediate就行:

`javascript

function debounceImmediate(func, delay, immediate = false) {

let timerId;

return function(...args) {

if (timerId) clearTimeout(timerId);

// 要是需要立即执行,且当前没定时器,就立刻跑函数

if (immediate && !timerId) func.apply(this, args);

// 不管有没有立即执行,都重置定时器

timerId = setTimeout(() => timerId = null, delay);

};

}

`

第二个是取消定时器:要是用户中途离开页面,或者不需要再触发函数了,可以用clearTimeout清除定时器,避免没必要的执行。比如搜索框失去焦点时,就可以取消未执行的防抖。

其实防抖不是什么复杂的黑科技,就是把“频繁触发的动作”按最后一次的时间点统一处理。平时做前端开发时,遇到频繁触发的场景(输入、滚动、窗口 resize),用个防抖就能轻松解决性能问题,让你的代码又省资源又好用。

上一篇 C / C++核心语法差异与应用场景科普 助你快速掌握系统开发利器