引用前人博客内容 《JavaScript高级程序》中关于函数节流概念的错误,本人也非常赞同作者关于写博客的态度。
另一篇释义清晰的文章 一定能看懂的函数防抖与函数节流。
两者概念辨别
函数节流和函数防抖在一些应用场景上有重合,导致新手比较难以分辨到底谁是谁,引用文中释义准确的定义:
- 函数节流 throttle 一个水龙头在滴水,可能一次性会滴很多滴,但是我们只希望它每隔 500ms 滴一滴水,保持这个频率。即我们希望函数在以一个可以接受的频率重复调用。
- 函数防抖 debounce 将一个弹簧按下,继续加压,继续按下,只会在最后放手的一瞬反弹。即我们希望函数只会调用一次,即使在这之前反复调用它,最终也只会调用一次而已。
比如以监听一个resize事件为例,连续地多次调节窗口的大小:
- 函数节流 throttle: 在你resize的过程中,每200ms就进行一次DOM调整响应。
- 函数防抖 debounce: 只有当你这一次resize整个过程完成之后,才进行一次DOM调整。
所以它们的这个属性天然决定了各自适合的应用场景:
- throttle-过程中:拖拽元素、搜索词联想(google/baidu每敲一个字母就会有响应)、canvas画板交互、屏幕向下滚动
- debounce-完成后: 文本输入校验(手机号、邮箱)、搜索词联想(部分低频响应场合的替代方案)、屏幕向下滚动
它们两者在某些场合都可以使用,但效果会有所差别。比如屏幕滚动onscroll这一块,有的站点用节流来做,可以让你一直不断的下拉屏幕,这对于快速浏览场景,找图片找新闻标题会很好;但是如果是在看某块完整内容,如一篇新闻一个章节小说,体验效果就会很差,这时就适合用防抖来做。
两者的目的都是为了节省非必要的消耗,提升响应性能和保证其他逻辑层的稳定执行(不会被大量DOM渲染或重复执行的回调事件而导致响应滞后)。
函数节流 throttle
示例代码:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Throttle Test</title>
</head>
<body style="height:200vh;">
<script>
const throttle = (func = ()=>{}, interval = 250) => {
let isFree = true;
return function () {
if (!isFree) return;
isFree = false;
setTimeout(() => { isFree = true }, interval); // 体会throttle是以一定频率来响应
if (func) func();
}
}
var scrollthrottle = throttle(() => console.log("Throttle Function"));
document.body.onscroll = scrollthrottle;
</script>
</body>
</html>
函数防抖 debounce
示例代码:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body style="height:200vh;">
<script>
const debounce = (func = ()=>{}, wait = 250) => {
let timer;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
if (func) func();
}, wait); // 体会debounce是滞后于事件响应之后的效果
}
}
var scrolldebounce = debounce(() => console.log('Debounce Function'));
document.body.onscroll = scrolldebounce;
</script>
</body>
</html>
增添一点区别:从代码中也可以看到,在节流中回调函数可以放在setTimeout里,也可放在外。而在防抖中只能放在setTimeout里了。注意到这点区别也是在不同场合使用不同方法的原因之一。
一句话总结
节流 过程中以一定频率执行回调,以一定频率连续响应
防抖 过程完成之后执行一次回调,在一段时间内只响应一次
网友评论