[性能优化]用装饰器实现截流与防抖

1,568 阅读1分钟

前言

造点小轮子, 提高开发效率, 截流与防抖可用于性能优化, 防止用户暴力交互

throttle

截流: 一定时间内, 任务不管被调用多少次, 只实际执行一次

export function throttle (duration: number = 0): Function {
 return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
    const rawFunction: Function = descriptor.value
    const getNewFunction: Function = (): Function => {
      let start: number = Date.now()
      const newFunction: Function = (...args) => {
        const now: number = Date.now()
        if (now - start >= duration) {
          start = now
          rawFunction.call(this, args)
        }
      }
      return newFunction
    }
    descriptor.value = getNewFunction()
    return descriptor
  }
}

debounce

防抖: 任务被调用后, 在一定延迟后才执行, 若再次被调用, 则重新计算延迟时间
缺点: 若用户一直暴力调用, 则一直不执行

export function debounce (delay: number): Function {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
    const rawFunction: Function = descriptor.value
    const getNewFunction: Function = (): Function => {
      let timer
      const newFunction: Function = (...args) => {
        if (timer) {
          window.clearTimeout(timer)
        }
        timer = setTimeout(() => {
          rawFunction.call(this, args)
        }, delay)
      }
      return newFunction
    }
    descriptor.value = getNewFunction()
    return descriptor
  }
}

throttleDebounce

用截流优化后的防抖: 若暴力调用, 一定时间内至少实际执行一次

function throttleDebounce (delay: number): Function {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {
    const rawFunction: Function = descriptor.value
    const getNewFunction: Function = (): Function => {
      let timer
      let start: number = Date.now()
      const newFunction: Function = (...args) => {
        const now: number = Date.now()
        if (now - start >= delay) {
          start = now
          rawFunction.call(this, args)
        } else {
          if (timer) {
            window.clearTimeout(timer)
          }
          timer = setTimeout(() => {
            rawFunction.call(this, args)
          }, delay)
        }
      }
      return newFunction
    }
    descriptor.value = getNewFunction()
    return descriptor
  }
}

demo

用法

class Test {

  @throttle(1000)
  throttleTest () {
    console.warn('throttleTest')
  }

  @debounce(1000)
  debounceTest () {
    console.warn('debounceTest')
  }

  @throttleDebounce(1000)
  throttleDebounce () {
    console.warn('throttleDebounce')
  }

}