vue+lodash:防抖和节流

597 阅读2分钟

一、什么是防抖,什么是节流

  • 防抖:用户多次触发事件,当停止时将事件执行一次 动图.gif
  • 节流:多次触发事件,在这个过程中每隔n秒执行一次 动图.gif

二、lodash中debounce函数的使用

1、安装

npm i --save lodash.debounce

2、导入

import debounce from 'lodash/debounce'

3、观察者模式防抖

    <input type="text" v-model="value">
  data() {
    return { value: '' }
  },
  watch: {
    value: {
      handler(val) {
        this.debounceWatch(val)
      }
    }
  },
  created() {
    this.debounceWatch = debounce((val) => {
      console.log(val)
    }, 500)
  },
  beforeDestroy() {
    this.debounceWatch.cancel()
  }

4、给事件回调函数添加防抖

    <input type="text" @input="handleInput">
  created() {
    this.handleInput = debounce((e) => {
      console.log(e.target.value)
    }, 500)
  },
  beforeDestroy() {
    this.handleInput.cancel()
  }

两种方式效果一样,如果是使用组件库,需要指定v-model

    <el-input v-model="value" @input="handleInput" />
    <van-field v-model='value' @input="handleInput" />

5、不推荐的写法

这样写会使函数的某个属性丢失,原因是methods中的方法会经过bind返回一个新的函数,此时原函数的属性在新函数中不存在

<template>
  <input type="text" @input="handleInput">
</template>
<script>
import debounce from 'lodash/debounce'
export default {
  methods: {
    handleInput: debounce(function (val) {
      console.log(val.target.value)
    }, 200)
  },
}
</script>

三、lodash中throttle函数的使用

1、安装

npm i --save lodash.throttle

2、导入

import throttle from 'lodash/throttle'

3、给事件回调函数添加节流

    <input type="text" @input="handleInput">
  created() {
    this.handleInput = throttle((e) => {
      console.log(e.target.value)
    }, 500)
  },
  beforeDestroy() {
    this.handleInput.cancel()
  }

4、播放音频时,高亮对应的节点

      this.wavesurfer.on('audioprocess', this.handleAudioprocess);

    handleAudioprocess (currentTime) {
      const regionList = Object.values(this.wavesurfer.regions.list);
      const timeScopeList = regionList.map(({ start, end }) => ({ start, end }));
      const index = timeScopeList.findIndex(({ start, end }) => start <= currentTime && currentTime <= end);
      console.log(index);
      this.active = index;
      if (index !== -1) {
        this.$refs.ulRef.scrollTop = index > 6 ? 36 * index : 0;
      };
    },
      

image.png

看啊,打印了好多次,咱们使用throttle优化一下:

      // this.wavesurfer.on('audioprocess', this.handleAudioprocess);
      this.wavesurfer.on('audioprocess', throttle(this.handleAudioprocess, 50));

使用throttle优化后,打印次数少多了 image.png

但其实这样写不推荐,推荐的写法是:

  created () {
    this.handleInput = throttle(this.handleAudioprocess, 50);
  },
  beforeDestroy () {
    this.handleInput.cancel();
  },
  
  ...
  
        this.wavesurfer.on('audioprocess', this.handleInput);

四、防抖函数的实现

用来监听resize事件

      window.addEventListener('resize', debounce(handle, 500))

      function handle() {
        console.log(document.body.clientWidth)
      }

如果一直在触发resize,需要清除掉定时器,直到停下来后重新定义setTimeout,500ms后执行fn

      function debounce(fn, delay) {
        var timer = null
        return function () {
          if (timer) clearTimeout(timer)
          var _this = this
          var _arguments = arguments
          timer = setTimeout(function () {
            fn.apply(_this, _arguments)
          }, delay)
        }
      }

五、节流函数的实现

通过setTimeout实现:

每隔500ms设置一次定时器,同时清除该定时器

      function throttle(fn, delay) {
        var timer = null
        return function () {
          var _this = this
          var _arguments = arguments
          if (!timer) {
            timer = setTimeout(function () {
              fn.apply(_this, _arguments)
              clearTimeout(timer)
              timer = null
            }, delay)
          }
        }
      }

通过时间戳实现:

在触发resize的过程中,当前时间减上一次时间如果大于等于500,执行一次fn,并且将上一次时间重置为当前时间

      function throttle(fn, delay) {
        var prevTime = Date.now()
        return function () {
          var curTime = Date.now()
          if (curTime - prevTime >= delay) {
            fn.apply(this, arguments)
            prevTime = Date.now()
          }
        }
      }