1.为什么要防抖和节流
- 举个简单的例子,很多网站的搜索框需要通过输入文本框的内容实时检索数据。每输入一个字符就会触发一次函数执行,因此函数的执行频率很高,很可能内容还没输入完就已经触发函数执行
- 然而实际上我们并不需要这么高频率的执行反馈,它会浪费浏览器性能,甚至可能牵涉后台请求而影响服务器性能;因此就有了使用防抖和节流来进行性能优化
防抖和节流一般在onresize、mousemove、滚动事件等事件中使用,防止过多的请求造成服务器压力
2.函数防抖(debounce)
一个需要频繁触发的函数,在规定时间内只让最后一次生效,前面不生效。也就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- 比如在输入框输入时,要搜索某个字符串,基于性能考虑,肯定不能用户没输入一个字符就发送一次搜索请求,使用的方法就是等待用户停止输入,比如过了500ms用户都没有再输入,那么就搜索此时的字符串,这就是防抖
代码实现
- 短时间内多次触发同个事件,只会执行一次函数。
- 函数防抖一般是指对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时。
- 使用setTimeout函数
采用非立即执行方式,确保获取到最新的输入框值,n秒内没有再次输入才会触发函数,否则重新倒计时n秒,直到n秒内没有再次输入的时候才会触发函数执行。function debounce(fn,delay){
var timer = null;
return function(){
clearTimeout(timer)// 清除上一延时器
timer = setTimeout(function(){// 重新设置新的延时器
fn()
},delay)
}
}
var ipt = document.querySelector('input')
ipt.oninput = debounce(function () {
console.log(ipt.value);
}, 1000)
3.节流(throttle)
所谓节流,是指频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数。指连续触发事件但是在 n 秒中只执行一次函数,所以节流稀释了函数执行的频率
- 类比到生活中的水龙头,拧紧水龙头到某种程度会发现,每隔一段时间,就会有水滴流出。
- 上面输入框例子中防抖的实现是n秒内不再输入则触发函数执行,然而如果我们一直保持n秒内输入,则将永远无法触发函数,如果希望即使用户不停输入,也能够在某个时间间隔反馈(触发函数),因此有了第二种解决思路:节流
使用时间戳实现节流(onscroll事件)
使用时间戳实现节流(onscroll事件)
fn: 要被节流的函数
delay:规定的时间
function throttle(fn,delay){
var lasttime = 0 ;// 记录上一次触发的时间
// 通过闭包的方式使用lasttime变量,每次都是上次的时间
return function(){
var nowtime = Date.now();
if(nowtime-lasttime>delay){
fn()// 调用函数
lasttime = nowtime; // 同步时间
}
}
}
document.onscroll = throttle(function(){
console.log("scroll事件被触发了"+Date.now());
}
,1000)
上方代码设置时间为1s,实现的效果,当滚动屏幕时控制台打印当前时间戳,虽然是一直滚动屏幕,但也是在时间周期1s后才会第二次输出当前时间戳。由此实现了函数的节流。
使用setTimeout实现节流(onmousemove事件)
使用setTimeout实现节流(onmousemove事件)
function throttle(fn, delay) {
let flag = false
return function () {
if (flag) {
return // 如果flag = false,那就直接不执行下边的代码
}
flag = true // 持续触发的话,flag一直是true,就会停在上边的判断那里
setTimeout(() => {
fn()// 定时器到时间之后,函数就会被执行
flag = false
}, delay)
}
}
var box=document.querySelector('.box')
box.onmousemove = throttle(function (e) {
console.log('onmousemove事件被触发了'+ Date.now());
}, 1000)
函数执行的前提条件是开关打开,持续触发时,持续关闭开关,等到setTimeout到时间了,再把开关打开,函数就会执行了。
4.防抖常见应用场景
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求。
- 手机号、邮箱验证输入检测。
窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
5.节流常见应用场景
滚动监听,返回顶部功能,即监听浏览器滚动事件,返回当前滚动条位置与顶部距离。可以采用节流方式,当滚动条滚动时以n秒的时间间隔获取当前位置与浏览器顶部距离。
- 按钮提交事件
懒加载要监听计算滚动条的位置,使用节流按一定时间的频率获取。
总结
防抖和节流都是为了解决频繁触发某个事件造成的性能消耗,在用户体验允许的情况下减少性能浪费。
- 函数防抖和节流区别在于
- 函数防抖的情况下,函数将一直推迟执行,造成不会被执行的效果;
- 函数节流的情况下,函数将每隔 n 秒执行一次
- 节流防抖就好比乘电梯,比如delay(等待)是10秒,那么防抖就是电梯每进来一个人就要等10秒再运行,而节流就是电梯保证每10秒可以运行一次
- 在项目中,至于选用防抖还是节流来降低性能损耗,可根据项目实际需求而定。