防抖和节流属于性能优化
,在进行窗口的resize
、滚动条scroll
,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。
此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。
函数防抖(debounce)
不管事件触发频率多高,一定在事件触发n
秒后才执行,如果你在一个事件触发的 n
秒内又触发了这个事件,就以新的事件的时间为准,n
秒后才执行。对于短时间内连续触发的事件,防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。
实现:
- 实现的关键就在于
setTimeout
这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。 - 里面的
setTimeout
则用的箭头函数,这样做的意义是让this
的指向准确,this
的真实指向并非debounce
的调用者,而是返回闭包的调用者。 - 对传入闭包的参数进行透传
function debounce(event, time) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(()=> {
event.apply(this, args);
}, time)
}
}
// 如果需要立即执行, 加一个flag 标志, 定时器变量`timer`为空时,说明是第一次执行,我们立即执行它。
function debounce(fn, time, flag) {
let timer = null;
return function(...args) {
clearTimeout(timer);
if(flag && !timer) {
fn.apply(this, args)
}
timer = setTimeout(()=> {
fn.apply(this, args);
}, time)
}
}
复制代码
应用场景:
1、窗口的resize
window.addEventListener('resize', debounce(handleResize, 200))
复制代码
2、滚动条scroll
function showTop() {
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log(scrolltop);
}
window.addEventListener('scroll', debounce(showTop, 1000))
复制代码
3、输入框内容校验
, 搜索框
debounce(valicator/fetchSelectData, 1000)
复制代码
函数节流(throttle)
当持续触发事件时,保证一定时间段内只调用一次事件处理函数.
节流好比水龙头放水,按照一定规律在某个时间间隔内一滴一滴的往下滴, 不开阀放水浪费;
函数节流主要有两种实现方法: 时间戳和定时器
;
时间戳实现:
首刻发生,尾刻不发生,中间正常
function throttle(event, time) {
let pre = 0;
return function(...args) {
if(Date.now() - pre > time) {
pre = Date.now();
event.apply(this, args);
}
}
}
复制代码
定时器实现
首刻不发生,尾刻发生,中间正常;
function throttle(event, time) {
let timer = null;
return function(...args) {
if(!timer) {
timer = setTimeout(()=>{
clearTimeout(timer)
timer=null;
event.apply(this, args);
}, time);
}
}
}
复制代码
结合
function throttle(event, time) {
let pre = 0, timer = null;
return function(...args) {
if(Date.now() - pre > time) {
pre= Date.now();
timer = null
clearTimeout(timer);
event.apply(this, args)
} else if(!timer) {
timer = setTimeout(()=>{
event.apply(this, args);
}, time);
}
}
}
复制代码