前言
日常的开发工作中,其实是很常需要用到防抖和节流的。比如浏览器滚动条的监听,表单的输入,或者是一些特定的会多次触发的场景。那么,防抖和节流的区别是什么呢,又该如何去实现?
防抖
含义:个人理解,防抖就是在一段时间内,只想触发一次事件,但事件有可能会被多次触发。比较典型的是在做模糊搜索的时候,期望实现的效果是用户输入停止的时候再进行请求,而不是用户每键入一个值就请求一次。这个时候就需要进行防抖,设定一个时间段,如果这个时间段内用户再次输入,则重置时间段,以此类推,只有当设定的这个时间段内再没有输入,才进行请求。那么如何实现呢?
具体实现:
既然是在一段时间内只是想执行一次,而且在这段时间内如果再次触发了要重置,那么,可以通过setTimeout来实现。
function debounce(fn, delay) {
// 这里通过闭包来保存变量timer,防止全局变量污染
let timer = null;
return () => {
// 不管是否存在定时器,都清掉重置一遍。
// 当然这里也可以判断是否存在定时器,存在再进行清除。
clearTimeout(timer)
timer = setTimeout(() => {
// 注意,这里使用的是箭头函数,所以这里的this指向没有改变。
// 如果使用的是普通函数需要在定时器外面保存this
fn.apply(this, arguments);
}, delay)
}
}
这样写有一个缺点就是,如果在设定的这个时间段内,事件一直都有触发,那么函数就会被一直delay。
节流
含义:个人理解,就是一段时间内,只调用一次函数,如果这段时间内函数再次被调用,则不执行。比较典型的是滚动加载更多,监听滚动条的滚动这个事件是非常之频繁的,就像水龙头开闸了一样 ,滚一下就哗啦啦的触发,如果不对其进行限制,是非常影响性能的。还有一个比较典型的是按钮的提交或者是其他一些用户可能会多次点击的事件。我们一般都会加一个判断条件,如果用户多次请求,只有在上一次请求完毕之后再进行请求,如果上一次请求还没有完成,则直接return。
function throttle(fn, delay) {
// 同防抖,防止变量污染
let loading = false
return () => {
// 只有当loading为false才执行
// loading为false则意为着上一个函数已经执行完毕
if (loading) return
loading = true
setTimeout(() => {
fn.apply(this, arguments)
loading= false
}, delay)
}
}
这里用setTimeout来模拟请求事件。实际开发中,一般是在请求后台之前将loading设置为true,请求后台完毕之后再设为false。
THE END