概念
节流 (throttle)与 防抖 (debounce)都是为了降低调用频率的一种方式。
相同点都是需要设置一个回调函数及周期时间,区别在于:
-
防抖是在停止触发后的100ms,执行一次(在此时间段内,只要不停止触发,理论上就永远不会触发回调)
-
节流是在不断的触发过程中,每隔100ms就执行一次。
下面简单画下流程图
节流 throttle
在高频触发回调函数时,节流操作使回调函数在每隔一段时间定期执行一次,时间间隔内再触发,不会重新执行。
核心在于让一个函数不要执行的太频繁,减少一些过快的操作。
类似于技能冷却时间 ⏱
/**
* 节流
* @param func
* @param wait
*/
function throttle(func: Function, wait: number) {
let timer: number = 0;
return (...args) => {
if (timer) { return }
timer = window.setTimeout(() => {
func(...args)
timer = 0
}, wait)
}
}
防抖 debounce
在高频触发回调函数时,防抖操作使回调函数在一定时间间隔内,再次触发会清空定时器,并重新计时;计时结束后输出一次结果。
核心在于,在短时间内大量触发同一事件时,只会执行一次回调函数。避免把一次事件误认为多次。
/**
* 防抖
* @param func
* @param wait
*/
function debounce(func: ()=>void, wait: number) {
let timer: number = 0
return (...args) => {
clearTimeout(timer)
timer = window.setTimeout(() => {
func(...args)
timer = 0; // 必须么??
}, wait)
}
}
tips: 注意 args 剩余参数的传递,否则执行回调函数时参数将丢失。
🌰 栗子
// 监听页面滚动条位置
const handleScrollTop = () => {
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
// 防抖:在停止滚动100ms后,才会输出滚动条位置
window.onscroll = debounce(handleScrollTop,100)
// 节流:每隔100ms都会输出一次滚动条位置
window.onscroll = throttle(showTop,100)
常见场景
- 监听 scroll、mousemove 等事件 - 节流(每隔一秒计算一次位置)
- 监听浏览器窗口 resize 操作 - 防抖(只需计算一次)
- 键盘文本输入的验证 - 防抖(连续输入文字后发送请求进行验证,验证一次就好)
- 提交表单 - 防抖(多次点击变为一次)
节流、防抖有时用哪个都可以,比如监听页面滚动,可以节流(每个一段时间出发一次回调),也可以防抖(用户当前这次滚动结束出发,继续滚动等待下一次触发)
React 中使用
- Class 组件中
需要注意调用节流/防抖函数位置,在组件初始化时就绑定节流/防抖事件,否则回调函数不会被触发。
constructor(props: any) {
super(props);
// 注意在此绑定!!
this.handleScroll = throttle(this.handleScroll, 100)
}
- 在函数式组件中,由于渲染的问题使用起来需要特别注意。可以参考
参考