函数防抖(debounce)
概念:就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- 简单的说,当一个动作连续触发,则只执行最后一次。
常见实用场景,有滚动加载、搜索框输入、窗口大小拖拽 Resize。
函数防抖的应用场景(连续的事件,只需触发一次回调):
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
- 为什么需要函数防抖:
- 前端开发过程中,有一些事件,常见的例如,**onresize**,**scroll**,**mousemove** ,**mousehover** 等,会被频繁触发(短时间内多次触发),不做限制的话,有可能一秒之内执行几十次、几百次,如果在这些函数内部执行了其他函数,尤其是执行了操作 DOM 的函数(浏览器操作 DOM 是很耗费性能的),那不仅会浪费计算机资源,还会降低程序运行速度,甚至造成浏览器卡死、崩溃。这种问题显然是致命的。除此之外,短时间内重复的 ajax 调用不仅会造成数据关系的混乱,还会造成网络拥塞,增加服务器压力,显然这个问题也是需要解决的。
- 怎么做
- 函数防抖的要点,是需要一个 **setTimeout** 来辅助实现,延迟运行需要执行的代码。如果方法多次触发,则把上次记录的延迟执行代码用 **clearTimeout** 清掉,重新开始计时。若计时期间事件没有被重新触发,等延迟时间计时完毕,则执行目标代码。
实例:
<body>
<span id="span"></span>
<script>
let count=0;
function demo(params) {
count++;
span.innerHTML=count;
}
function debounce(fn,delay) {
let timer;
return function () { //定义一个匿名函数,return返回的是一个函数,
if(timer){ //判断timer是否有值
clearTimeout (timer); //清除掉之前的定时器的数据
}
timer=setTimeout(fn,delay); //重新生成定时器,也就是说我定义的一秒,就重新开始计时一秒
}
}
//原理:只有当1秒内没有重新触发这个事件才可以进行计算
window.addEventListener("resize",debounce(demo,1000)) //当屏幕尺寸发生改变的时候,触发该事件,
</script>
</body>
函数节流(throttle)
概念:指连续触发事件多次,但是在n秒内只执行一次函数,
函数节流的应用场景(间隔一段时间执行一次回调):
- 滚动加载,加载更多或滚到底部监听
- 谷歌搜索框,搜索联想功能
- 高频点击提交,表单重复提交
<body>
<div id="div1">
</div>
<span id="span"></span>
<script>
let count=0;
function fn(params) {
if(count===50){
return;
}
count++;
span.innerHTML=count;
}
function throttle(fn,delay) {
let status=true; //标识 是否可以干活
return function (params) {
if(!status){ //判断是否可以操作
return
}
status=false; //干活之后设置状态,为不允许在操作
setTimeout(()=>{
fn(); //重新调用fn函数
status=true; //又开始干活
},delay)
}
}
div1.onmousemove=throttle(fn,1000)
</script>
</body>
函数防抖和函数节流异同比较
相同点:
- 都可以通过使用 setTimeout 实现。
- 目的都是,降低回调执行频率。节省计算资源。
不同点:
- 函数防抖,在一段连续操作结束后,处理回调,利用 clearTimeout 和 setTimeout 实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。
- 函数防抖关注一定时间连续触发,只在最后执行一次,而函数节流侧重于一段时间内只执行一次。
为了辅助理解,我们首先通过一个可视化的工具,感受一下三种环境(正常情况、函数防抖情况 debounce、函数节流 throttle)下,对于mousemove事件回调的执行情况。
竖线的疏密代表事件执行的频繁程度。可以看到,正常情况下,竖线非常密集,函数执行的很频繁。而debounce(函数防抖)则很稀疏,只有当鼠标停止移动时才会执行一次。throttle(函数节流)分布的较为均已,每过一段时间就会执行一次。
想看相信的可以去看看涂鸦码龙写的实例解析防抖动(Debouncing)和节流阀(Throttling) https://jinlong.github.io/2016/04/24/Debouncing-and-Throttling-Explained-Through-Examples/