1. 简介
防抖debounce
与节流throttle
是在一些执行频率较高的交互或事件处理中的性能优化
场景一:输入框获取到内容自动请求获取数据
场景二:拖动窗口变大或者缩小
在这些连续交互变化的场景中,若不加防抖或者节流操作,会导致事件频发,浪费性能,加上防抖节流操作后,事件就可以等待用户操作完触发,这样就节省了很多性能。
2. 防抖与节流的对比
debounce
debounce
有一个等待时长,若在等待时间内再次调用了函数,则取消上一个定时器,新建一个定时器重新计时
适用场景:input、keyup、keydown等事件,或者某个需要防止用户多次点击的场景。
在lodash库中,并没有取消、新建等时期的做法,它是用时间来判断的
代码实现:
function debounce(fn, wait) {
let callback = fn;
let timerId = null;
function debounced() {
// 保存作用域
let context = this;
// 保存参数,例如 event 对象
let args = arguments;
clearTimeout(timerId);
timerId = setTimeout(function() {
callback.apply(context, args);
}, wait);
}
// 返回一个闭包
return debounced;
}
// test
let resizeFun = function(e) {
console.log('resize');
};
window.addEventListener('resize', debounce(resizeFun, 500));
什么是闭包?
闭包有三步:
第一,外层函数嵌套内层函数;
第二, 内层函数使用外层函数的局部变量;
第三,把内层函数作为外层函数的返回值! 经过这样的三步就可以形成一个闭包! 闭包就可以在全局函数里面操作另一个作用域的局部变量!闭包的作用?
闭包既能重复使用局部变量,又不污染全局!
throttle
throttle
也有一个等待时长,在用户持续触发事件的过程中,函数每隔一段时间都会执行一次函数,若事件处理函数没有处理完时事件依旧在触发,则它会忽略下次调用该函数的请求。
适用场景:窗口变化、鼠标移动事件
代码实现:throttle
相对于debounce
最大区别就是不会取消上一次函数的执行
相同点
都是利用函数延迟执行来实现效果,可以理解为使用了setTimeout
举个🌰:
使用 lodash
处理 resize
事件时,在wait
参数不是非常小的情况下:
用debounce
的话,会在用户停止改变浏览器窗口大小时触发,也就是只是在最后触发一次。
用throttle
的话,会在用户改变浏览器窗口大小的过程中,每隔一段时间触发一次。
其实在 lodash 的实现中: throttle 就是一个定义了最大等待时长的 debounce。
function throttle(fn, wait) {
let callback = fn;
let timerId = null;
// 是否是第一次执行
let firstInvoke = true;
function throttled() {
let context = this;
let args = arguments;
// 如果是第一次触发,直接执行
if (firstInvoke) {
callback.apply(context, args);
firstInvoke = false;
return ;
}
// 如果定时器已存在,直接返回。
if (timerId) {
return ;
}
timerId = setTimeout(function() {
// 注意这里 将 clearTimeout 放到 内部来执行了
clearTimeout(timerId);
timerId = null;
callback.apply(context, args);
}, wait);
}
// 返回一个闭包
return throttled;
}
// test
let resizeFun = function(e) {
console.log('resize');
};
window.addEventListener('resize', throttle(resizeFun, 500));