Skip to content

手写防抖和节流

防抖

js
function debounce(func, delay, immediate = false) {
  if (typeof func !== "function") {
    throw new TypeError("Expected a function");
  }

  if (typeof delay !== "number" || delay < 0) {
    throw new TypeError("Expected delay to be a positive number");
  }

  let timer = null;

  const debounced = function (...args) {
    const context = this;
    clearTimeout(timer);

    if (immediate) {
      const callNow = !timer;
      timer = setTimeout(() => {
        timer = null;
      }, delay);

      if (callNow) {
        func.apply(context, args);
      }
    }
    else {
      timer = setTimeout(() => {
        func.apply(context, args);
      }, delay);
    }
  };

  // 添加取消方法
  debounced.cancel = function () {
    clearTimeout(timer);
    timer = null;
  };

  return debounced;
}

节流

js
function throttle(func, delay, options = {}) {
  if (typeof func !== "function") {
    throw new TypeError("Expected a function");
  }

  if (typeof delay !== "number" || delay < 0) {
    throw new TypeError("Expected delay to be a positive number");
  }

  let timer = null;
  let previous = 0; // 上次执行的时间点

  // 解构配置项,leading表示是否立即执行,trailing表示是否在结束后执行
  const { leading = true, trailing = true } = options;

  const throttled = function (...args) {
    const now = Date.now();
    const context = this;

    // 如果是第一次调用且leading为false,则将上次执行时间设为当前时间
    if (!previous && leading === false) {
      previous = now;
    }

    const remaining = delay - (now - previous);

    if (remaining <= 0 || remaining > delay) {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      previous = now;
      func.apply(context, args);
    }
    else if (!timer && trailing) {
      timer = setTimeout(() => {
        previous = leading ? Date.now() : 0;
        timer = null;
        func.apply(context, args);
      }, remaining);
    }
  };

  // 添加取消方法
  throttled.cancel = function () {
    clearTimeout(timer);
    timer = null;
    previous = 0;
  };

  return throttled;
}