JavaScript函数防抖(Debounce)原理与应用实战
JavaScript函数防抖(Debounce)旨在解决短时间内频繁触发事件导致的性能问题。其核心逻辑是利用定时器延迟任务执行,若期间再次触发则重置计时器,从而确保仅在静止状态后执行一次操作。
防抖动简述
函数防抖动(debounce):防止在短时间内过于频繁地执行相同的任务。当短时间内的频繁触发是不必要的时候,就可以考虑去抖动,避免资源浪费或造成不好的用户体验。
函数防抖动的原理,主要是利用一次性定时器,延迟任务的执行。在延迟这段时间内,如果任务再次被触发,则通过 clearTimeout 销毁上一次产生的定时器。因为定时器的被销毁,之前被延迟执行的任务也会随之被取消执行。这样就实现了在一定时间内,只执行一次任务。这一次的执行通常是最后一次的触发,因为此前的触发因为定时器的销毁而被取消了。
多次触发只执行最后一次或许就是和“节流”概念的区别?它们两在作用上挺像的,在具体实现上略有不同。函数防抖(debounce)是短时间内连续多次触发,但只执行最后一次,即是说将多次执行变成了只执行最后一次,执行次数减少。而节流(throttle)是将短时间的多次执行,变成每隔一段时间执行一次。
防抖应用示例
第1步:查看防抖前后效果对比
第2步:构建防抖完整Demo
以下是一个基于 input 事件的防抖示例,演示如何对表单输入进行实时校验而不产生过多计算开销。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>防抖动 Demo</title>
</head>
<body>
<h1>防抖动 Demo</h1>
<label>
<span>输入昵称:</span>
<input oninput="inputChange(event.data)"></input>
</label>
<script>
let timer = null
function inputChange (data) {
// 不做防抖动会频繁触发校验,例如连续的输入两个字可能会触发6-7次,
// 这种频繁程度可能不是必要的,当频繁不是必要的,那么就是资源的浪费。
// validatePhone(data)
// 防抖处理,连续正常的输入同样的两个字,只会触发一次校验任务。
clearTimeout(timer)
timer = setTimeout(() => {
validatePhone(data)
}, 1000)
}
function validatePhone (data) {
let flag = true
const regPhone = /^1\d{10}$/
if (!regPhone.test(data)) {
flag = false
console.log('校验内容:' + data + '。手机号不正确,请输入1开头的11位手机号')
}
return flag
}
</script>
</body>
</html>防抖动的应用场景
当任务在短时间内被频繁执行,而这种频繁不是必要的,或不是想要的,就可以考虑使用防抖。下面是一些场景例子:
1. 监听滚动条联动导航
①监听滚动条实现左侧内容和右侧导航关联,滚动条的频繁程度很高,而这种频繁程度可能不是我们想要的,此时就可以考虑使用防抖。
例如我在 JavaScript实现内容滚动与导航标签互动关联方案中就使用了防抖。
// 监听滚动条
window.addEventListener("scroll", function (e) {
// 防抖动处理
clearTimeout(that.timeout)
this.timeout = setTimeout(() => {
that.activeNavNode(e)
}, 100)
});2. 表单输入监听
②表单输入的一些监听事件,例如 oninput 等。
3. 组件库内容变化监听
③一些组件库的内容变化监听,例如 el-tree 的 @check-change 事件,当选择祖先级的选项时,因为包含了选中其子孙项,@check-change 会被频繁触发,如果这个选项变化关联接口,那么这种频繁可能不是必要的。
下面是一个示例:
<el-tree
ref="tree"
:data="treeData"
show-checkbox
@check-change="handleCheckChange">
</el-tree>handleCheckChange (data, checked, indeterminate) {
// 简单的防抖动处理
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
let checkedKeys = this.$refs.tree.getCheckedKeys()
// 处理相关业务,例如根据选中的条件,触发接口查询
// this.$emit('checkChange', checkedKeys.join(';'))
}, 300)
},4. 监听浏览器窗口大小变化
④监听浏览器窗口变化 window.onresize,例如在 echarts 的应用中,默认浏览器窗口大小改变 echarts 视图布局是不会做响应式改变的,那么就需要通过监听浏览器窗口大小改变然后去重置 echarts 实现布局的改变。实践发现,调整一下浏览器窗口大小,会非常多次触发 onresize,但如果我们也跟着去多次重置 echarts.resize(),这不仅不是必要的,而且还会造成闪烁频繁,卡顿等不好的体验,以及性能浪费。此时适合用防抖动处理。
下面是一个示例:
// 设备视口大小改变时,重置 echarts
let timer = null
window.onresize = function () {
// 简单的防抖动处理
clearTimeout(timer)
timer = setTimeout(() => {
console.log(timer)
chart.resize()
}, 500)
}也可以考虑使用闭包的方式,而不必在外面声明 timer,例如这样:
// 也可以考虑用闭包的方式
window.onresize = this.debounce(() => {
chart.resize()
}, 500)
function debounce (fn, delay = 1000) {
let timer = null
return () => {
if (timer) clearTimeout(timer)
timer = setTimeout(fn, delay)
}
}5. 鼠标拖拽事件监听
⑤鼠标事件,例如拖拽等的监听等,出于准确性和及时性,它们的监听响应十分细密,而当这种频繁在业务上可能不是必要的,那么也可以考虑使用防抖动技术。
以上就是JavaScript函数防抖动debounce的详细内容,更多关于JS防抖动优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













