防抖和节流

98 阅读2分钟

防抖就是指在连续的触发过程中,只执行一次响应,这个【连续的触发过程】没有时间限制,如果一直触发,那么消抖就没结束;

节流是指在一个时间段内,只执行一次响应,和防抖不同的是,如果在【连续的触发过程】中,是可能不止一次响应的,取决于截流时间。

防抖和截流还可以细分为立即执行和非立即执行两种情况,没有特殊情况,两种选其一即可。

选用一个现成的项目vue-template-admin,页面添加一个按钮,添加一个点击事件来模拟点击操作。

防抖

非立即执行版:编辑/src/utils/debounce.js

export const debounce = (fun, delay) => {
  let timeout
  return (params) => {
    if (timeout) {
      clearTimeout(timeout)
    }
    timeout = setTimeout(() => {
      fun.call(this, params)
    }, delay)
  }
}

在连续触发的过程中,如果已经给timeout赋值了,就清空,再重新赋值timeout,这样就能一直更新timeout,直到连续触发的过程结束,最后延时函数结束后就执行里面的fun函数

编辑dashboard/index.vue

<template>
  <el-button @click="handleClick(222)">Click me</el-button>
</template

import{ debounce } from '@/utils/debounce'
export default {
  data() {
    return {
      myFun: null
    }
  }
  methods: {
    handleClick(value){
      console.log('click')
      if(!this.myFun){
        this.myFun = debounce(this.getData, 500)
      }
      this.myFun()
    },
    getData(args) {
      console.log(`args=${args}`)
    }
  }
}

连续点击,只响应最后一次事件,并且参数也传进去了

debounce1.png

立即执行版:

export const debounce2 = (fun, delay) => {
  let timeout
  return (params) => {
    if (!timeout) fun.call(this, params)
    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => {
      timeout = null
    }, delay)
  }
}

在连续触发的过程中,如果timeout为空,就先执行一次fun,然后给timeout赋值,在接下来的过程中不断的给timeout重新赋值,直到连续触发的过程结束,然后延时函数结束,再清空timeout,等待下次触发。

查看结果:

debounce2.png

节流

立即执行版:

export const throttle = (fun, delay) => {
  let flag = true
  return (params) => {
    if (flag) {
      fun.call(this, params)
      flag = false
      setTimeout(() => {
        flag = true
      }, delay)
    }
  }
}

维护一个flag标志,在连续的触发过程中,flag为true的时候就执行fun方法,执行完就清空flag等待倒计时结束后再把flag置为true,不论这个过程有多长,只要在设定的时间间隔内都会调用fun

查看结果:

debounce3.png

// 也可以直接用timeout做标志位
export const throttle2 = (fun, delay) => {
  let timeout
  return (params) => {
    if (!timeout) {
      fun.call(this, params)
      timeout = setTimeout(() => {
        timeout = null
      }, delay)
    }
  }
}

非立即执行:

export const throttle3 = (fun, delay) => {
  let timeout
  return (params) => {
    if (!timeout) {
      timeout = setTimeout(() => {
        fun.call(this, params)
        timeout = null
      }, delay)
    }
  }
}

把fun放到timeout回调里,就是非立即执行的了,他会等倒计时函数结束才执行。

查看结果:

debounce4.png