javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS防抖动

JavaScript函数防抖动debounce

作者:​ 灵扁扁

这篇文章主要介绍了JavaScript函数防抖动debounce,防抖动作用防止在短时间内过于频繁的执行相同的任务,更多相关内容需要的小伙伴可以参考一下

防抖动简述

函数防抖动(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)
  }
}

⑤鼠标事件,例如拖拽等的监听等,出于准确性和及时性, 他们的监听响应十分细密,而当这种频繁在业务上可能不是必要的,那么也可以考虑使用防抖动技术。

到此这篇关于JavaScript函数防抖动debounce的文章就介绍到这了,更多相关JS防抖动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文