前言:
浏览器的resize、scroll、keypress、mousemove等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。防抖和节流都是通过减少对事件绑定的回调函数的调用频率来实现的。
函数防抖(debounce)
概念:在事件被触发n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时。
应用场景如:以用户拖拽窗口大小,触发resize事件为例,在这个resize过程中窗口的大小一直在改变,所以如果我们在resize事件中绑定回调函数,这个函数将会不断被触发,而这种情况大多数情况下是无意义的,还会造成资源的大量浪费。
生活实例:
如果有人进电梯,那电梯将会等10s后出发,在这等待的10s内,如果又有人进电梯了,那么电梯又得等10s才会触发。
防抖实现:
// 函数防抖相关代码
function debounce(func, delay) {
// 维护一个定时器
let timer = null;
return function () {
let context = this;
let args = arguments;
timer && clearTimeout();
timer = setTimeout(function () {
func.apply(context, args);
}, delay);
}
}
函数节流(throttle)
概念:规定在一定时间段内,只能有一次触发事件的回调函数执行,如果在该时间段内某事件被触发多次,只有一次能生效。也就是在一段时间内只允许函数执行一次。
应用场景如:输入框的联想,可以限定用户在输入时,只在每两秒钟响应一次联想。
生活实例:
节流实现:节流可以通过时间戳和定时器来实现。
// 时间戳实现函数节流
function throttle(func, delay) {
let prev = Date.now();
return function () {
let context = this;
let args = arguments;
let now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
// 定时器实现函数节流
function throttle(func, delay) {
let timer = null;
return function () {
let context = this;
let args = arguments;
if (!timer) {
timer = setTimeout(function () {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
两种方式的区别在于,使用时间戳实现的节流函数会在第一次触发事件的时候立即执行,以后每过delay秒之后才执行一次,并且最后一次触发事件回调函数不会执行;而定时器实现的节流函数在第一次触发时不会执行,而是在delay秒之后才执行,当最后一次停止触发后,还会再执行一次函数。
优秀参考资源链接: