Skip to content

js - 防抖和节流


debounce

创建一个防抖函数。

参数

  • fn: Function - 需要防抖的函数

  • delay: number - 延迟时间,单位毫秒,默认300

  • immediate: boolean - 是否立即执行,默认false

返回值

  • Function - 防抖后的函数,包含cancel方法用于取消防抖

使用示例

javascript

// 基础用法

const debouncedFn = debounce(() => console.log('触发'), 300);

window.addEventListener('resize', debouncedFn);

  

// 取消防抖

debouncedFn.cancel();

throttle

创建一个节流函数。

参数

  • fn: Function - 需要节流的函数

  • interval: number - 间隔时间,单位毫秒,默认300

  • options: Object - 配置选项

  • leading: boolean - 是否第一次立即执行,默认true

  • trailing: boolean - 是否最后一次执行,默认true

返回值

  • Function - 节流后的函数,包含cancel方法用于取消节流

使用示例

javascript

// 基础用法

const throttledScroll = throttle(() => console.log('滚动'), 300);

window.addEventListener('scroll', throttledScroll);

  

// 自定义首尾是否执行

const throttledMove = throttle(

() => console.log('移动'),

300,

{ leading: false, trailing: true }

);

源码

js
/**
 * 防抖函数 - 在最后一次触发后延迟执行
 * @param {Function} fn - 需要防抖的函数
 * @param {number} delay - 延迟时间,单位毫秒
 * @param {boolean} immediate - 是否立即执行
 * @returns {Function} 防抖后的函数
 *
 * @example
 * // 基础用法
 * const debouncedFn = debounce(() => console.log('触发'), 300)
 * window.addEventListener('resize', debouncedFn)
 *
 * // 立即执行
 * const debouncedClick = debounce(
 *   () => console.log('点击'),
 *   300,
 *   true
 * )
 * button.addEventListener('click', debouncedClick)
 *
 * // 取消防抖
 * debouncedClick.cancel()
 */
function debounce(fn, delay = 300, immediate = false) {
  let timer = null
  let isInvoke = false

  const _debounce = function (...args) {
    if (timer) clearTimeout(timer)

    // 第一次是否立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, args)
      isInvoke = true
      return
    }

    timer = setTimeout(() => {
      fn.apply(this, args)
      isInvoke = false
      timer = null
    }, delay)
  }

  // 取消功能
  _debounce.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    isInvoke = false
  }

  return _debounce
}
js
/**
 * 节流函数 - 按时间间隔执行
 * @param {Function} fn - 需要节流的函数
 * @param {number} interval - 间隔时间,单位毫秒
 * @param {boolean} leading - 是否第一次立即执行
 * @param {boolean} trailing - 是否最后一次执行
 * @returns {Function} 节流后的函数
 *
 * @example
 * // 基础用法
 * const throttledScroll = throttle(
 *   () => console.log('滚动'),
 *   300
 * )
 * window.addEventListener('scroll', throttledScroll)
 *
 * // 自定义首尾是否执行
 * const throttledMove = throttle(
 *   () => console.log('移动'),
 *   300,
 *   { leading: false, trailing: true }
 * )
 * element.addEventListener('mousemove', throttledMove)
 *
 * // 取消节流
 * throttledMove.cancel()
 */
function throttle(fn, interval = 300, { leading = true, trailing = true } = {}) {
  let startTime = 0
  let timer = null

  const _throttle = function (...args) {
    const nowTime = Date.now()

    // 第一次是否需要立即执行
    if (!leading && startTime === 0) {
      startTime = nowTime
    }

    const remainTime = interval - (nowTime - startTime)
    if (remainTime <= 0) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      fn.apply(this, args)
      startTime = nowTime
      return
    }

    // 最后一次是否需要执行
    if (trailing && !timer) {
      timer = setTimeout(() => {
        fn.apply(this, args)
        startTime = Date.now()
        timer = null
      }, remainTime)
    }
  }

  // 取消功能
  _throttle.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    startTime = 0
  }

  return _throttle
}

Released under the MIT License.