func.js 3.47 KB
/**
 * 防抖函数(debounce)
 * 核心:触发后延迟执行,中途再次触发则重置延迟时间,只执行最后一次
 * @param {Function} fn - 要防抖的目标函数
 * @param {number} delay - 延迟时间(毫秒),默认500ms
 * @param {boolean} immediate - 是否立即执行一次(第一次触发时执行,后续触发延迟),默认false
 * @returns {Function} 包装后的防抖函数
 */
export function debounce(fn, delay = 500, immediate = false) {
  let timer = null; // 存储定时器ID

  // 返回包装后的函数
  const debounced = function (...args) {
    // 保存this指向(确保原函数this指向不变)
    const context = this;

    // 如果有正在等待的定时器,清除它(重置延迟)
    if (timer) clearTimeout(timer);

    // 立即执行的逻辑
    if (immediate) {
      // 是否已经执行过(第一次触发时执行)
      const callNow = !timer;
      // 设置定时器:delay时间后清空timer,允许下次触发立即执行
      timer = setTimeout(() => {
        timer = null;
      }, delay);
      // 第一次触发时执行函数
      if (callNow) fn.apply(context, args);
    } else {
      // 非立即执行:每次触发都重置定时器,delay后执行
      timer = setTimeout(() => {
        fn.apply(context, args);
      }, delay);
    }
  };

  // 新增取消防抖的方法(可选,用于手动终止)
  debounced.cancel = function () {
    clearTimeout(timer);
    timer = null;
  };

  return debounced;
}

/**
 * 节流函数(throttle)
 * 核心:固定时间内只执行一次,到点必触发,不重置时间
 * @param {Function} fn - 要节流的目标函数
 * @param {number} interval - 执行间隔(毫秒),默认500ms
 * @param {Object} options - 配置项
 * @param {boolean} options.leading - 是否允许首次触发执行,默认true
 * @param {boolean} options.trailing - 是否允许最后一次触发延迟执行,默认true
 * @returns {Function} 包装后的节流函数
 */
export function throttle(fn, interval = 1000, options = { leading: true, trailing: true }) {
  let timer = null; // 存储定时器ID
  let lastCallTime = 0; // 上一次执行函数的时间

  // 返回包装后的函数
  const throttled = function (...args) {
    const context = this;
    const now = Date.now(); // 当前时间

    // 如果禁用首次执行,且是第一次触发,初始化lastCallTime为当前时间
    if (!lastCallTime && !options.leading) lastCallTime = now;

    // 计算距离下次可执行的剩余时间
    const remainingTime = interval - (now - lastCallTime);

    // 剩余时间<=0:到了执行时间,直接执行
    if (remainingTime <= 0) {
      // 清除之前的定时器(防止trailing触发)
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      // 执行目标函数
      fn.apply(context, args);
      // 更新上一次执行时间
      lastCallTime = now;
    } else if (options.trailing && !timer) {
      // 剩余时间>0,且允许最后一次执行:设置定时器延迟执行
      timer = setTimeout(() => {
        // 如果禁用首次执行,重置lastCallTime(避免重复触发)
        lastCallTime = options.leading ? Date.now() : 0;
        fn.apply(context, args);
        timer = null;
      }, remainingTime);
    }
  };

  // 新增取消节流的方法(可选)
  throttled.cancel = function () {
    clearTimeout(timer);
    timer = null;
    lastCallTime = 0;
  };

  return throttled;
}