防抖节流
- 面试时,面试官问:网络环境差的情况,如何防止用户多次点击?
- 没想过防抖节流的方法,回答完,面试官反问使用过防抖节流处理过吗???
- 没有!!!防抖节流是啥都了解不清楚!!!
防抖与节流的原理
防抖节流是前端应用开发中常见的功能!是利用闭包,缓存延迟时间。主要应用场景就是会频繁触发的事件,如浏览器的resize(窗口大小变化)、scroll,鼠标的mousemove、mouseover,input输入框键盘事件等,不断地调用绑定在事件上的回调函数,极大的浪费资源,降低性能。需要对这类事件进行调用次数的限制,优化体验。
防抖debounce
不停触发事件,但是它一定在事件触发n秒后才执行,如果在一个事件触发的n秒内又触发了该事件,则累计时间清零,以新事件触发的时间为准,再过n秒后才执行。总之,就是 要等你触发事件完n秒内不在触发,才执行
打个比方:景区入园,规定每5秒,进入一批;
- 来了一批人,进去,后面的人要5秒后才可以进入
- 过了1秒又来了一批人,不能进,累计时间清零(重置定时器),还要等5秒后
- 过了2秒又来了一批人,不能进,累计时间再清零,还要再等5秒
- 5秒后,可以进入了 (实际等待时间:1+2+5秒)
function debounce (func, delay = 5000) { // delay = 5000设置默认值
let timer = null
return function () {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, arguments) // 直接用this,因为使用箭头函数
timer = null
}, delay)
}
}
document.querySelector('#div').onmousemove = debounce(function Fn(event){
console.log(this)
console.log(event)
})
- 以上代码的逻辑就是:判断是否存在定时器,存在就清除定时器,然后重新定义一个定时器,定时器到时间再执行Fn函数
- 代码中使用到了闭包,主要目的是为了函数执行后保留timer这个变量在局部作用域,不污染全局变量。
问:为什么要返回一个函数?
试了下没有返回函数的写法:删掉debounce函数中的return,把timer提到全局变量(为了保留timer)
let timer = null
function debounce(func, delay) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, arguments)
timer = null
}, delay)
}
// document.querySelector('#div').onmousemove = debounce(function Fn(event){
// console.log(this)
// console.log(event)
// })
// 执行代码后,看见就只执行了一次!!!
// 在debounce函数里面返回一个函数,因为onmousemove需要的是未执行的函数。 如下写法,也可让debounce函数一定时间后就执行
document.querySelector('#div').onmousemove = function Fn(event){
debounce(() => {
console.log(this)
console.log(event)
})
}
这种写法和第一个debounce函数通过闭包方式返回一个函数结果一样,推荐使用第一种,闭包写法可以避免变量的全局污染
节流throttle
防抖和节流本质上是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
当触发事件的时候,设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行函数,清空定时器,才可以再设置下一个定时器
照样是景区入园的例子:规定每5秒进去一批
- 来了一批人,进入
- 过1秒来一批,需要等待4秒,进入
- 又过1秒来一批,需要等待3秒,进入
function throttle (func, delay = 5000) {
let timer = null
return function () {
if (timer) return
timer = setTimeout(() => {
func.apply(this, arguments)
timer = null
}, delay)
}
}
document.querySelector('#div').onmousemove = throttle(function Fn(event){
console.log(this)
console.log(event)
})
防抖节流应用场景
防抖
适用于:连续的事件,只需要触发一次回调的场景
- 输入框输入。只需要用户最后一次输入完后,在发送请求。(手机号、邮箱验证等输入校验)
- 浏览器窗口大小resize。只需要窗口调整完成后,计算窗口大小。防止重复渲染。
节流
适用于:间隔一段时间执行一次回调的场景
- 浏览器滚动加载、加载更多、滚动到底部监听
- 搜索联想功能
- 高频点击,表单重复提交
参考:
js防抖节流详解和应用