Open felix-cao opened 5 years ago
防抖动(debounce)与节流(throttle) 都是在特殊的场景下限制函数的执行次数,以优化事件触发频率过高导致的函数的响应速度跟不上事件的触发频率,出现延迟,假死或卡顿的现象。
debounce 是为了限制在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。实际上在我们的生活中有这样的一个案例,坐电梯:
debounce
n
如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),在我们等到第 5 秒时,又有人进电梯了(在10秒内再次触发该事件),那刚等的5秒就浪费了,我们就又得等10秒再出发(重新计时)。
下面是这个场景的代码行为:
/** * @param fn {Function} 实际要执行的函数 * @param delay {Number} 延迟时间,也就是阈值,单位是毫秒(ms) * @return {Function} 返回一个“去弹跳”了的函数 */ function debounce(fn, delay) { var timer; // 定时器,用来 setTimeout // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数 return function () { // 保存函数调用时的上下文和参数,传递给 fn var context = this var args = arguments clearTimeout(timer) // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作), // 再过 delay 毫秒就执行 fn timer = setTimeout(function () { fn.apply(context, args) }, delay) } }
其实思路很简单, debounce 返回了一个闭包,这个闭包依然会被连续频繁地调用,但是在闭包内部,却限制了原始函数 fn 的执行,强制 fn 只在连续操作停止后只执行一次。
fn
节流是规定一个间隔时间,在这个时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
/** * @param fn {Function} 实际要执行的函数 * @param delay {Number} 执行间隔,单位是毫秒(ms) * @return {Function} 返回一个“节流”函数 */ function throttle(fn, threshhold) { var last; // 记录上次执行的时间 var timer; // 定时器 threshhold || (threshhold = 250) // 默认间隔为 250ms // 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数 return function () { // 保存函数调用时的上下文和参数,传递给 fn var context = this var args = arguments var now = +new Date() // 如果距离上次执行 fn 函数的时间小于 threshhold,那么就放弃 // 执行 fn,并重新计时 if (last && now < last + threshhold) { clearTimeout(timer) // 保证在当前时间区间结束后,再执行一次 fn timer = setTimeout(function () { last = now fn.apply(context, args) }, threshhold) // 在时间区间的最开始和到达指定间隔的时候执行一次 fn } else { last = now fn.apply(context, args) } } }
要牵涉到连续事件或频率控制相关的应用都可以考虑到这两个函数,比如:
input
ajax
resize
window
scroll
throttle
防抖动(debounce)与节流(throttle) 都是在特殊的场景下限制函数的执行次数,以优化事件触发频率过高导致的函数的响应速度跟不上事件的触发频率,出现延迟,假死或卡顿的现象。
一、 防抖动(debounce)
debounce
是为了限制在事件被触发n
秒后再执行回调,如果在这n
秒内事件又被触发,则重新计时。实际上在我们的生活中有这样的一个案例,坐电梯:如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),在我们等到第 5 秒时,又有人进电梯了(在10秒内再次触发该事件),那刚等的5秒就浪费了,我们就又得等10秒再出发(重新计时)。
下面是这个场景的代码行为:
其实思路很简单,
debounce
返回了一个闭包,这个闭包依然会被连续频繁地调用,但是在闭包内部,却限制了原始函数fn
的执行,强制fn
只在连续操作停止后只执行一次。二、节流(throttle)
节流是规定一个间隔时间,在这个时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
下面是这个场景的代码行为:
三、使用场景
要牵涉到连续事件或频率控制相关的应用都可以考虑到这两个函数,比如:
input
中输入文字自动发送ajax
请求进行自动补全:debounce
resize
window
重新计算样式或布局:debounce
scroll
时更新样式,如随动效果:throttle
最重要的还是理解两者对调用时间及次数上的处理,根据业务逻辑选择最合适的优化方案!