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
相关产品推荐
相关产品推荐

