一文搞清楚 防抖 和 节流 函数

参考:
https://blog.csdn.net/weixin_48594833/article/details/123460177
https://www.jianshu.com/p/c8b86b09daf0 <— 必看
基础参考:
https://zhuanlan.zhihu.com/p/676609830

概念说明

防抖节流
定义一定时间内,动作连续触发情况下,动作只执行一次,都是触发n秒之后执行动作,(立即执行就是先执行一遍)一定时间内,只给执行一次动作(加锁不给执行)
作用限制执行次数,防止卡顿、延迟、假死等
原理刷新定时器,在定时器里面定时器结束才能执行fn一段时间内,加锁不给执行fn
实现都可以使用 setTimeout + clearTimeout 实现
场景用户输入事件等多是监听dom滚动等高触发事件。多是和后端有关。
用户一直触发时定时器一直重新赋值,执行<=1(立即执行版会先执行一次)n秒内会执行一次

代码实现

<template>
  <div class="test">
    <div class="content" @mousemove="fn4">
      {{ num }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'test',
  data() {
    return {
      num: 1,
      fn1: this.debounce(this.count, 2000), // 只有这样才有用
      fn2: this.debounceI(this.count, 2000), // 只有这样才有用
      fn3: this.throttle(this.count, 2000), // 只有这样才有用
      fn4: this.throttleT(this.count, 2000), // 只有这样才有用
    }
  },
  // created() {
  // },
  methods: {
    count() {
      console.log('count')
      this.num++
    },
    count1() {
      console.log('count1')
      this.debounce(this.count, 2000)() // 错误,每次move都会绑定一个定时器,只是延迟2秒触发一系列count
    },
    // 防抖:"频繁触发”一个事件时,limit 毫秒内只执行一次
    // 非立即执行的防抖函数
    debounce(fn, limit) {
      let time
      return function () {
        let context = this
        let args = arguments
        if (time) clearTimeout(time) // 触发时,如果有锁, 就清除掉,以最新生成的锁(定时器)为准
        time = setTimeout(() => {
          fn.apply(context, args)
        }, limit) // 每次都更新 time(锁), 定 limit 之后执行函数,将其推到堆中执行
      }
    },
    // 立即执行的防抖函数
    debounceI(fn, limit) {
      let time
      return function () {
        let context = this
        let args = arguments
        if (time) clearTimeout(time) // 如果有旧锁,把锁去掉
        let callNow = !time // 锁是否加上
        time = setTimeout(() => {
          time = null
        }, limit) // 赋值新锁,limit 之后解除锁
        if (callNow) fn.apply(context, args) // 没锁的时候执行
      }
    },
    // 合并: 防抖函数
    debounceFinal(fn, limit, immediate) {
      let time
      return function () {
        let context = this
        let args = arguments
        if (time) clearTimeout(time)
        if (immediate) {
          // 立即执行, limit ms 内不能再执行
          var callNow = !time
          time = setTimeout(() => {
            time = null
          }, limit)
          if (callNow) fn.apply(context, args)
        } else {
          // 延迟limit之后执行,值得注意的是:以频繁触发的最后一次为开始时间计算
          time = setTimeout(() => {
            fn.apply(context, args)
          }, limit)
        }
      }
    },
    // 节流:连续触发事件时 n 秒只执行一次函数
    // 时间戳版
    throttle(fn, limit) {
      let previous = 0
      return function () {
        let now = Date.now()
        let context = this
        let args = arguments
        if (now - previous > limit) {
          fn.apply(context, args) // 函数会立即执行,并且每 limit ms 执行一次
          previous = now
        }
      }
    },
    // 定时器版
    throttleT(func, limit) {
      let timeout
      return function () {
        let context = this
        let args = arguments
        if (!timeout) {
          timeout = setTimeout(() => {
            timeout = null
            func.apply(context, args) // 函数不会立即执行,并且每 kimit ms 执行一次,在停止触发事件后,函数还会再执行一次。
          }, limit)
        }
      }
    },
    // 合并: 节流函数
    throttleFinal(func, limit, type) {
      let previous = 0
      let timeout
      return function () {
        let context = this
        let args = arguments
        if (type === 1) {
          let now = Date.now()
          if (now - previous > limit) {
            func.apply(context, args)
            previous = now
          }
        } else if (type === 2) {
          if (!timeout) {
            timeout = setTimeout(() => {
              timeout = null
              func.apply(context, args)
            }, limit)
          }
        }
      }
    },
    /*

    */
  },
}
</script>

<style>
.content {
  height: 150px;
  line-height: 150px;
  text-align: center;
  color: #fff;
  background-color: #ccc;
  font-size: 80px;
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值