防抖和节流

使用场景

有时,我们会绑定一些持续触发的事件,如:resize、scroll、mousemove等,但是我们并不希望在事件持续触发的过程中那么频繁的去执行函数。通常情况下怎么去解决呢?一般来讲,防抖和节流是比较好的解决方案。

下面,我就已在vue中的input函数为例,讲解一下防抖和节流。

防抖

所谓防抖,就是指触发事件后在n秒内,函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行的时间。

其实防抖函数并不难写,下面这就是一个最初级的防抖函数:

<template>
  <div id="app">
    <el-input @input.native="inputFn" v-model='msg'></el-input>
  </div>
</template>

<script>
export default {
  components: {},
  data(){
    return{
      msg: '',
      timeout: ''
    }
  },
  methods: {
    // 最初级的防抖
    inputFn(e){
      if(this.timeout) clearTimeout(this.timeout)
      this.timeout = setTimeout(() => {
        console.log('执行函数')
      }, 3000)
    }
  }
}
</script>

接下来,我们利用闭包改造一下这个防抖函数,不要将timeout定义在函数外面了

<template>
  <div id="app">
    <el-input @input.native="inputFn" v-model='msg'></el-input>
  </div>
</template>

<script>
export default {
  components: {},
  data(){
    return{
      msg: '',
      timeout: '',
      delay: ''
    }
  },
  mounted(){
    // 初始化防抖函数
    this.delay = this.debounceFun(this.requestFun, 3000)
  },
  methods: {
    inputFn(e){
      this.delay('传入的参数')
    },
    // 第二版,非立即执行
    // 非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
    debounceFun(func, wait){
      let timeout = ''
      return function(){
        let context = this
        let args = arguments
        if(timeout) clearTimeout(timeout)
        timeout = setTimeout(() => {
          func.apply(context, args)
        }, wait)
      }
    },
    requestFun(data){
      console.log(data)
      console.log('执行函数')
    }
  }
}
</script>

这样,我们就把防抖函数写好了,是不是很简单

这面的这种是非立即执行版的,下面我们再来改造一下,实现一版立即执行版的防抖函数

立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。

// 第三版:立即执行
    // 立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
    debounceFun(func, wait){
      let timeout = ''
      return function(){
        let context = this
        let args = arguments
        // 记录当前是否存在timeout,如果不存在,则说明是第一次
        let isNow = !timeout
        if(timeout) clearTimeout(timeout)
        timeout = setTimeout(() => {
          func.apply(context, args)
        }, wait)
        // 如果不存在timeout,说明是第一次触发,则执行一次回调函数
        if(isNow) func.apply(context, args)
      }
    }

下面,我们再来写一版立即执行和非立即执行的合并版

// 第四版
// 当immediate为true时,是立即执行版;当immediate为false时,是非立即执行版
debounceFun(func, wait, immediate){
      let timeout = ''
      return function(){
        let context = this
        let args = arguments
        // 记录当前是否存在timeout,如果不存在,则说明是第一次
        let firstFlag = !timeout
        if(timeout) clearTimeout(timeout)
        timeout = setTimeout(() => {
          func.apply(context, args)
        }, wait)
        if(immediate){
          // 如果不存在timeout,说明是第一次触发,则执行一次回调函数
          firstFlag && func.apply(context, args)
        }
        
      }
    }

 

节流

所谓节流,就是指连续触发事件,但是在n秒钟只执行一次的函数。节流会稀释函数的执行频率

throttleFun(func, wait){
  let timeout = ''
  return function(){
    let context = this
    let args = arguments
    if(!timeout){
      timeout = setTimeout(() => {
        timeout = null
        func.apply(context, args)
      }, wait)
    }
  }
}

 

posted @ 2019-12-02 20:53  王小溪  阅读(424)  评论(0编辑  收藏  举报