You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Underscore库debounce方法不符合预期,如何实现每秒仅调用一次的函数?

关于Underscore.js防抖(debounce)函数的行为疑问

我正尝试理解debounce(防抖)的工作原理,但它的表现与我的预期不符。原本预期该防抖函数每秒仅能被调用一次,result元素会每秒更新当前count值,但它仅执行一次,result始终显示0。我是否误解了该函数的工作机制?

示例代码

JavaScript 代码

const fn = _.debounce(
  () => {
    document.getElementById("result").innerHTML = count
    count += 1
  },
  1000,
  true
);

let count = 0

function loop() {
  setTimeout(loop, 0);
  fn();
}

loop();

HTML 代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.6/underscore-min.js"></script>
<div>
  Hello World
</div>
<div id="result"></div>

问题原因

你使用了Underscore debounce的第三个参数true,这个参数代表**立即执行(leading edge)**模式。在这种模式下:

  • 防抖函数会在第一次调用时立刻执行目标函数
  • 之后的所有调用,只要在**冷却期(1000ms)**内连续触发,都会被忽略
  • 只有当冷却期结束后,再次调用才会重新触发执行

而你的代码里,loop函数通过setTimeout(loop, 0)形成了一个无限循环,在浏览器的事件循环中,这个循环会持续高频调用fn(),导致防抖函数的冷却期永远无法结束——第一次调用执行后,后续的调用全在1000ms冷却期内,所以不会再触发目标函数,自然count只增加到1,页面显示0。

解决方案

根据你的预期(每秒执行一次),适合改用节流(throttle)函数:
如果你的需求是每隔固定时间执行一次,这其实是节流(throttle)的场景,而非防抖。Underscore的_.throttle专门处理这种高频调用下的间隔执行需求:

const fn = _.throttle(
  () => {
    document.getElementById("result").innerHTML = count
    count += 1
  },
  1000
);

let count = 0

function loop() {
  setTimeout(loop, 0);
  fn();
}

loop();

这样修改后,fn会每隔1000ms执行一次,result会每秒更新一次数值。

防抖与节流的核心区别

  • 防抖(debounce):将高频触发的事件合并为一次,在最后一次触发后等待指定时间执行,适合输入验证、窗口 resize 等场景。
  • 节流(throttle):限制事件在指定时间内只能执行一次,适合滚动监听、鼠标移动等需要持续触发但控制频率的场景。

内容的提问来源于stack exchange,提问作者zrbecker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:05:15