「 在线演示 」防抖与节流

813 阅读2分钟

防抖

指触发事件n秒后再执行回调,若在n秒之内再次被触发,则重新计时。

手写实现防抖

function debounce(fn, delay) {
  let timer
  return function() {
    let that = this
    let args = arguments
    if(timer) clearTimeout(timer)
    timer = setTimeout(function() {
      fn.apply(that, args)
    }, delay)
  }
}

应用

由定义可知,防抖主要是为了解决事件频繁触发的问题,且仅采取频繁触发的最后一次操作。

常用场景:

  1. 输入框联想。
  2. 窗口resize事件。

vue3为例, 针对el-input@input事件进行防抖,接口临时写的,没有返回值,主要还是让大家感受下防抖前后的现象。还有在线Demo,亲身体验,点我 🙌。

ezgif.com-gif-maker (2).gif

<template>
  <div class="debounce-throttle">
    <div class="case-one">
      <div class="title">未防抖Input</div>
      <el-input v-model="caseStateOne" placeholder="请输入内容" @input="notDebounceSearchAsync"></el-input>
    </div>
    <div class="case-two">
      <div class="title">防抖Input</div>
      <el-input v-model="caseStateTwo" placeholder="请输入内容" @input="debounceSearchAsync"></el-input>
    </div>
  </div>
</template>
<script setup>
import { getDebounceOrThrottle } from '@/api/api.js'
import { ref } from 'vue'
let caseStateOne = ref('')
let caseStateTwo = ref('')
/**
 * @description: 防抖函数
 * @param {*} fn
 * @param {*} delay
 * @return {*}
 */
const debounce = function (fn, delay) {
  let timer
  return function () {
    let that = this
    let args = arguments
    if (timer) clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(that, args)
    }, delay)
  }
}
/**
 * @description: 未防抖远程搜索函数
 * @param {*} queryString
 * @param {*} cb
 * @return {*}
 */
const notDebounceSearchAsync = async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}
/**
 * @description: 防抖远程搜索函数
 * @param {*} queryString
 * @param {*} cb
 * @return {*}
 */
const debounceSearchAsync = debounce(async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}, 1000)
</script>

lodash 中的 debounce

lodash是一个JavaScript工具库,也提供了防抖函数。既然有成熟的库,为何不用呢?

import _ from 'lodash'
const lodashDebounceSearchAsync = _.debounce(async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}, 1000)

节流

规定在n秒内,只能触发一次回调。若在n秒内触发多次函数,只有第一次生效

手写节流

定时器写法

function throttle(fn, delay) {
  let timer
  return function() {
    let that = this
    let args = arguments
    if(timer) return 
    timer = setTimeout(function() {
      fn.apply(that, args)
      timer = null
    }, delay)
  }
}

时间戳写法

function throttle(fn, delay) {
  let last = 0
  return function() {
    let that = this
    let args = arguments
    let now = +new Date()
    if(now - last > delay) {
      fn.apply(that, delay)
      last = now
    }
  }
}

应用

由定义可知,节流也是为了解决事件频繁触发的问题,且仅采取频繁触发的第一次操作。

常用操作:

  1. 鼠标交互事件
  2. 滚动事件

vue3为例, 针对el-button@click事件进行防抖,接口临时写的,没有返回值,主要还是让大家感受下防抖前后的现象。还有在线Demo,亲身体验,点我🙌。 ezgif.com-gif-maker (2).gif

<template>
  <div class="debounce-throttle">
   <div class="case">
      <div class="title">未节流</div>
      <el-button @click="notThrottleSearchAsync">点我</el-button>
    </div>
    <div class="case">
      <div class="title">节流</div>
      <el-button @click="throttleSearchAsync">点我</el-button>
    </div>
    <div class="case">
      <div class="title">lodash节流</div>
      <el-button @click="lodashThrottleSearchAsync">点我</el-button>
  </div>
</template>
<script setup>
import { getDebounceOrThrottle } from '@/api/api.js'
import { ref } from 'vue'
/**
 * @description: 节流点击函数
 * @param {*} queryString
 * @param {*} cb
 * @return {*}
 */
const throttleSearchAsync = throttle(async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}, 1000)
/**
 * @description: lodash节流点击函数
 * @param {*} queryString
 * @param {*} cb
 * @return {*}
 */
const lodashThrottleSearchAsync = _.throttle(async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}, 1000)
/**
 * @description: 未节流点击函数
 * @param {*} queryString
 * @param {*} cb
 * @return {*}
 */
const notThrottleSearchAsync = async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}
</script>

lodash 中的 throttle

import _ from 'lodash'
const lodashThrottleSearchAsync = _.throttle(async function () {
  let result = await getDebounceOrThrottle()
  console.log('result:', result)
}, 1000)