浅析防抖与节流

41 阅读1分钟

一、前言

  • 防抖:类似于王者荣耀的回城,一直点是没有用的,只执行最后一次;
  • 节流:类似于王者的技能冷却,点之后的一段时间内再次点击是无效的;

  • 防抖执行最后一次,节流执行第一次;

二、代码实现

2.1、防抖

/** 任意类型的 Function */
type AnyFunction = (...args: any[]) => any
/** 表示防抖后的函数类型 */
type DebouncedFunction<T extends AnyFunction> = (...args: Parameters<T>) => ReturnType<T>

/**
 * 创建防抖函数
 * @param {Function} callback 原始函数
 * @param {Number} delay 防抖延时
 * @param {Boolean} immediate 是否立即执行
 * @returns {Function} 防抖后的函数
 */
function debounce<T extends AnyFunction>(callback: T, delay: number, immediate = false) {
  // 通过闭包缓存一个定时器 id
  let timer: NodeJS.Timeout | null

  const _debounce = function (this: ThisParameterType<T>, ...args: Parameters<T>) {
    // 如果已经设定过定时器就清空上一次的定时器
    if (timer) clearTimeout(timer)

    // 如果需要立即执行,且之前未执行过,则立即执行原始函数
    if (immediate && !timer) {
      callback.apply(this, args)
      timer = setTimeout(() => (timer = null), delay)
    } else {
      // 设置新的定时器,在延迟结束时执行原始函数
      // 使用保存的上下文和参数执行原始函数 箭头函数 所以可以直接用上级作用域的值
      timer = setTimeout(() => {
        timer = null
        callback.apply(this, args)
      }, delay)
    }
  }

  // 返回防抖后的函数,并根据原始函数的类型来断言返回函数的类型
  return _debounce as DebouncedFunction<T>
}

2.2、节流

/** 任意类型的 Function */
type AnyFunction = (...args: any[]) => any
/** 表示节流后的函数类型 */
type ThrottledFunction<T extends AnyFunction> = T

/**
 * 创建节流函数
 * @param {Function} callback 原始函数
 * @param {Number} delay 节流延时
 * @returns {Function} 节流后的函数
 */
function throttle<T extends AnyFunction>(callback: T, delay: number) {
  let timestamp = Date.now()
  const _throttle = function (this: ThisParameterType<T>, ...args: Parameters<T>) {
    const now = Date.now()
    if (Date.now() - timestamp > delay) {
      callback.apply(this, args)
      timestamp = now
    }
  }
  return _throttle as ThrottledFunction<T>
}