vue 中的 method 实现函数防抖的坑

135 阅读1分钟

vue 中的 method 实现函数防抖的坑

函数防抖是当函数在重复触发时, 只执行一次. 以此减少不必要的执行, 优化体验. lodash提供了 debounce 和 throttle 方法, 分别用于实现函数的防抖和节流. 在最近维护的一个内开源vue项目中. 发现大量的节流用法是错误的. 因此记录下正确的用法.

错误演示1

在线演示: codesandbox.io/s/vue-metho…

原来使用如下的写法. 当页面上引用多个该组件的时候, 发现同时点击这些按钮后. 有些组件在点击后未能触发节流函数.

<template>
<h1>vue 方法的节流的错误用法1</h1>
<button @click="clickDebounce">click</button>
</template>

<script>
import { debounce } from 'lodash'

export default {
  name: "App",
  methods: {
    clickDebounce: debounce(function () {
      console.log('click')
    }, 1000),
  }
};
</script>

该写法的问题在于, 在组件被引入的时候生成了一个节流函数, 每个组件实例化之后的 clickDebounce 方法都指向了同一个节流函数. 因此当同时引入多个该组件的时候, 会同时调用同一个节流函数. 导致有些组件的方法未能触发

错误演示2

在线演示: codesandbox.io/s/vue-metho…

<template>
<h1>vue 方法的节流的错误用法2</h1>
<button @click="clickDebounce">click</button>
</template>

<script>
import { debounce } from 'lodash'

export default {
  name: "App",
  props: {
    compId: String
  },
  methods: {
    clickDebounce(){
      const fn = debounce(function () {
        console.log('click')
      }, 1000)
      fn()
    }
  }
};
</script>

该写法的问题在于, vue 方法每次调用时都会生成一个新的节流函数, 1000ms 以后触发console. 因此无法实现节流的效果

正确的写法

在线演示: codesandbox.io/s/vue-metho…

比较简单的正确用法, 就是自己通过 setTimeout 实现一个节流函数.

<template>
<h1>实现 vue 方法的节流(正确用法)</h1>
<button @click="clickDebounce">click</button>
</template>

<script>

export default {
  name: "Right",
  methods: {
    clickDebounce() {
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        console.log('click')
      }, 1000)
    }
  }
};
</script>