JS防抖动
灵扁扁 人气:0防抖动简述
函数防抖动(debounce):防止在短时间内过于频繁的执行相同的任务。 当短时间内的频繁是不必要的时候,就可以考虑去抖动,避免资源浪费,或造成不好体验。
函数防抖动的原理,主要是利用一次性定时器,延迟任务的执行,在延迟这段时间内, 如果任务再次被触发,则通过 clearTimeout 销毁上一次产生的定时器, 因为定时器的被销毁,之前被延迟执行的任务也会随之被取消执行。 这样就实现了在一定时间内,只执行一次任务。这一次的执行通常是最后一次的触发, 因为此前的触发因为定时器的销毁而被取消了。
多次触发只执行最后一次或许就是和“节流”概念的区别?它两在作用上挺像的,在具体实现上略有不同。 函数防抖(debounce)是短时间内连续多次触发,但只执行最后一次,即是说将多次执行变成了只执行最后一次,执行次数减少。 而节流(throttle)是将短时间的多次执行,变成每隔一段时间执行一次。
防抖应用示例
1.防抖前后示例效果截图
2.防抖示例完整 demo
<!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>
防抖动的应用场景
当任务在短时间内被频繁执行,而这种频繁不是必要的,或不是想要的,就可以考虑使用防抖。 下面是一些场景例子:
①监听滚动条实现左侧内容和右侧导航关联,滚动条的频繁程度很高, 而这种频繁程度可能不是我们想要的,此时就可以考虑使用防抖。
例如我在 JavaScript实现内容滚动与导航标签互动关联方案中就使用了防抖。
// 监听滚动条 window.addEventListener("scroll", function (e) { // 防抖动处理 clearTimeout(that.timeout) this.timeout = setTimeout(() => { that.activeNavNode(e) }, 100) });
②表单输入的一些监听事件,例如 oninput 等。
③一些组件库的内容变化监听,例如 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) },
④监听浏览器窗口变化 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) } }
⑤鼠标事件,例如拖拽等的监听等,出于准确性和及时性, 他们的监听响应十分细密,而当这种频繁在业务上可能不是必要的,那么也可以考虑使用防抖动技术。
加载全部内容