来源:浅谈函数防抖与节流
在说防抖和节流之前,我们先看看下面这个例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
#count{
width: 100%;
height: 200px;
background-color: #5555ff;
color: #fff;
font-size: 69px;
padding-top: 50px;
text-align: center;
}
</style>
</head>
<body>
<div id="count"></div>
<script type="text/javascript">
var div = document.getElementById('count')
var count = 0
function add(){
count++
div.innerHTML = count
}
/* 监听鼠标移动事件 */
div.onmousemove = add
</script>
</body>
</html>
效果:
可以看到,只要鼠标移动就会触发事件add,我们在频繁的触发这个函数。其实在前端开发的过程中,我们经常会用到这种持续触发的事件,比如监听滚动条滚动,监听浏览器窗口缩放等,这些事件如果处理不当可能会造成浏览器卡死。我们不希望去频繁触发这些事件,防抖和节流能帮我们解决这种问题!
1. 防抖
防抖:指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
以mousemove为例:
如果在300ms以内没有触发鼠标移动事件,则执行函数;
如果在300ms以内再次触发了鼠标移动事件,则当前的计时取消,重新开始计时。
防抖的效果:某个时间段内频繁触发同一事件,该事件只会执行一次。
防抖的实现:将前面的例子中的js部分修改为如下代码
<script type="text/javascript">
var div = document.getElementById('count')
var count = 0
function add(){
count++
div.innerHTML = count
}
div.onmousemove = debounce(add,300)
/* 防抖 利用到了闭包 */
function debounce(fn,delay){
let timer = null
return function(){
if(timer){
clearTimeout(timer)/*再次触发取消之前的计时*/
timer = setTimeout(fn,delay)/*重新计时*/
}else{
timer = setTimeout(fn,delay) /*开始计时*/
}
/* 将以上代码化简 */
/*if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay)*/
}
}
</script>
修改后的效果:
可以看到我们的鼠标一直移动时不会触发事件,当鼠标停止移动才会触发。这就解决了之前频繁触发事件的问题!
2. 节流
根据上面的例子,我们不难想出如果使用防抖的解决办法,那么当我们的鼠标一直移动的时候,我们的数字始终不会变化。这种情况也可能发生在当我们不停滚动滚动条的时候,我们的“回到顶部”按钮一直不会出现、或者当我们不停地调节浏览器窗口来适配不同样式的时候,样式始终不会改变。显然,上述的几个例子出现的现象并不是我们希望的效果。
我们希望在不停地调节浏览器窗口大小或者滑动滚动条的时候,既要防止频繁触发事件,又要让这些事件在一定时间间隔内执行。这时我们可以利用节流来帮助我们解决问题。
节流:指连续触发事件但是在 n 秒中只执行一次函数。节流会减小函数的执行频率。
节流的效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间间隔内不再工作,直至过了这个时间段才重新生效。
节流的实现:
<script type="text/javascript">
var div = document.getElementById('count')
var count = 0
function add(){
count++
div.innerHTML = count
}
div.onmousemove = throttle(add,700)
/* 节流 也利用了闭包*/
function throttle(fn,delay){
let flag = true
return function(){
if(!flag){
return false
}
flag = false
setTimeout(()=>{
fn()
flag = true
},delay)
}
}
</script>
效果:
可以看到,在持续触发事件的过程中,函数不会立即执行,而是每间隔700ms执行一次。
3. 应用场景举例
函数防抖:
在用户注册时手机号和邮箱验证,只有用户输入完成后,才需要检测格式是否正确,如果不正确,再弹出提示语。
函数节流:
在监听页面元素滚动事件的时候会用到,滚动事件是一个高频触发的事件。
搜索框input事件,例如要支持输入实时搜索可以使用节流方案查询相关内容。