每天一道题:简简单单快速理解函数节流和函数防抖
❝作者:bibi不吃鱼 今日的许多烦恼,都来源于昨日的惰性。
❞
什么是函数节流?
现实场景举例子
我们知道玩游戏的时候有个设定叫垂直同步,可以强制要求游戏画面的刷新率限制在 60fps 以内,这样我们的显卡就不会在每次渲染游戏画面的时候,拼劲全力渲染最高帧数。
60fps 既可以满足大家的肉眼游戏需求,还可以让显卡一直稳定工作,不至于一直高强度工作,大大提升了显卡的使用寿命。
当1秒60帧就可以满足人类需求的时候,渲染到 100,200,300 就造成了资源上面的浪费,电的浪费,显卡寿命的缩短等等。(注:现在玩一些射击游戏的可能会用144HZ,追求高刷新率)
实际应用场景
- 一个可拖曳的DOM元素(mousemove)
- 王者荣耀或者LOL里面的 技能释放CD(单位时间只能释放一次技能)
- 滚动事件,(页面滚动,间隔判断一次)
- 搜索联想
手写函数节流(以页面滚动为例子)
这里以判断页面是否滚动到底部为例子,普通的做法就是监听 window 对象的 scroll 事件,然后在函数体中写入判断是否滚动到底部的逻辑:
// 判断是否滚动到底部的逻辑
const pageHeight = $('body').height();
const scrollTop = $(window).scrollTop();
const winHeight = $(window).height();
const thresold = pageHeight - scrollTop - winHeight;
if (thresold > -100 && thresold <= 20) {
console.log('end');
}
}
$(window).on('scroll', onScroll);
这样做的一个缺点就是比较消耗性能,因为当在滚动的时候,浏览器会无时不刻地在计算判断是否滚动到底部的逻辑,而在实际的场景中是不需要这么做的。
在实际场景中可能是这样的:在滚动过程中,每隔一段时间在去计算这个判断逻辑。
而函数节流所做的工作就是每隔一段时间去执行一次原本需要无时不刻地在执行的函数,所以在滚动事件中引入函数的节流是一个非常好的实践:
接着看一下加入函数节流的效果吧
什么是函数防抖?
现实场景举例子
坐公交车,假设公交车一次只能拉一个人,50 个人要坐公交车的话公交车就要路线走 50 次才能拉完这些人,这就是一种浪费资源的行为。一般我们在现实生活中,公交车到站了,司机会一直等待到没有人想要坐公交车了,才开车出发。(相对于之前的一次只拉一个人,这次的一直要在一个站拉到没人要坐为止,就是一种节约资源的方式)
实际应用场景
- 窗口大小resize(只需窗口调整完成后,计算窗口大小,防止重复渲染)
- 滚动事件scroll(只需执行触发的最后一次滚动事件的处理程序
- 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,(停止输入后)验证一次就好
手写函数防抖(以页面滚动为例子)
这里以一个文章缓存功能为例子。如果一个网站比如石墨文档,要实现用户打字后自动上传到服务器并保存的功能,如果用户每输入一个字符就去向服务器申请保存一次,上万甚至上千万百万用户一起使用的时候,就会大大增加服务器的负荷。
那我们应该怎么节省资源来做这件事呢?我们应该找一个时间,当用户停止输入一段时间的时候再去申请一次服务器保存,这样就大大节省了多次申请带来的资源浪费,而且我们也保存到了用户的正常输入内容。
我们如何去判断一个用户已经停止了输入呢?当然是通过我们的输入框,如果在我们限定的时间段内,输入框的内容没有发生任何变化,那我们就可以认为用户停止输入了,就可以向服务器申请保存了。
const input = document.querySelector('input');
input.addEventListener('input', function() {
clearTimeout(timer);
timer = setTimeout(function() {
//保存
}, 800)
})
总结
函数节流: 频繁触发,但只在特定的时间内才执行一次代码
函数防抖: 频繁触发,但只在特定的时间内没有触发执行条件才执行一次代码
两者区别在于函数节流是固定时间做某一件事,比如每隔1秒发一次请求。而函数防抖是在频繁触发后,只执行一次(两者的前提都是频繁触发)
如果对你有帮助的话,请点个👍吧!
本文使用 mdnice 排版