JS节流与防抖

节流防抖

// 节流函数 (最后一次不执行)
// 立即执行 在单位时间内只触发一次事件
const throttle = (method, delay) => {
  let timer = null;
  let start = false;
  return function () {
    if (!start) {
      start = true;
      method.apply(this, arguments);
      timer = setTimeout(() => {
        start = false;
      }, delay);
    }
  };
};

// 节流函数(最后一次执行)
// 立即执行 在单位时间内只触发一次事件 执行最后一次
const throttle = (method, delay) => {
  let timer = null;
  let start = Date.now();
  return function () {
    let now = Date.now();
    clearTimeout(timer);
    if (now - start >= delay) {
      method.apply(this, arguments);
      start = now;
    } else {
      timer = setTimeout(() => {
        method.apply(this, arguments);
        start = Date.now();
      }, delay);
    }
  };
};

// 防抖函数(立即执行版)
// 先执行一次 在事件被触发单位时间内 又被触发 则重新计时
const debounce = (method, delay) => {
  let timer = null;
  let start = Date.now();
  return function () {
    let now = Date.now();
    clearTimeout(timer);
    if (now - start >= delay) {
      method.apply(this, arguments);
      start = now;
    } else {
      timer = setTimeout(() => {
        method.apply(this, arguments);
      }, delay);
      start = now;
    }
  };
};

// 防抖函数(延迟执行版)
// 在事件被触发单位时间内 又被触发 则重新计时
const debounce = (method, delay) => {
  let timer = null
  return function () {
    clearTimeout(timer)
    timer = setTimeout(() => {
      method.apply(this, arguments)
    }, delay)
  };
};

 

function isObject (value) {
  let type = typeof value;
  return value !== null && (type === 'object' || type === 'function')
}
const root = window;
function now () {
  return root.Date.now()
}
let Symbol = root.Symbol;
let objectProto = Object.prototype;
let hasOwnProperty = objectProto.hasOwnProperty;
let nativeObjectToString = objectProto.toString;
let symToStringTag = Symbol ? Symbol.toStringTag : undefined;
function getRawTag (value) {
  let isOwn = hasOwnProperty.call(value, symToStringTag);
  let tag = value[symToStringTag];
  let unmasked = false;
  try {
    value[symToStringTag] = undefined;
    unmasked = true;
  } catch (e) {
    return
  }
  let result = nativeObjectToString.call(value);
  if (unmasked) {
    if (isOwn) {
      value[symToStringTag] = tag;
    } else {
      delete value[symToStringTag];
    }
  }
  return result
}
let objectProto$1 = Object.prototype;
let nativeObjectToString$1 = objectProto$1.toString;
function objectToString (value) {
  return nativeObjectToString$1.call(value)
}
let nullTag = '[object Null]';
let undefinedTag = '[object Undefined]';
let symToStringTag$1 = Symbol ? Symbol.toStringTag : undefined;
function baseGetTag (value) {
  if (value == null) {
    return value === undefined ? undefinedTag : nullTag
  }
  return (symToStringTag$1 && symToStringTag$1 in Object(value))
    ? getRawTag(value)
    : objectToString(value)
}
function isObjectLike (value) {
  return value !== null && typeof value === 'object'
}
const symbolTag = '[object Symbol]';
function isSymbol (value) {
  return typeof value == 'symbol' ||
    (isObjectLike(value) && baseGetTag(value) === symbolTag)
}
let NAN = 0 / 0;
let reTrim = /^s+|s+$/g;
let reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
let reIsBinary = /^0b[01]+$/i;
let reIsOctal = /^0o[0-7]+$/i;
let freeParseInt = parseInt;
function toNumber (value) {
  if (typeof value == 'number') {
    return value
  }
  if (isSymbol(value)) {
    return NAN
  }
  if (isObject(value)) {
    let other = typeof value.valueOf === 'function' ? value.valueOf() : value;
    value = isObject(other) ? (other + '') : other;
  }
  if (typeof value !== 'string') {
    return value === 0 ? value : +value
  }
  value = value.replace(reTrim, '');
  let isBinary = reIsBinary.test(value);
  return (isBinary || reIsOctal.test(value))
    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
    : (reIsBadHex.test(value) ? NAN : +value)
}
const nativeMax = Math.max;
const nativeMin = Math.min;
function debounce (func, wait, options) {
  let lastArgs;
  let lastThis;
  let maxWait;
  let result;
  let timerId;
  let lastCallTime;
  let lastInvokeTime = 0;
  let leading = false;
  let maxing = false;
  let trailing = true;
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function')
  }
  wait = toNumber(wait) || 0;
  if (isObject(options)) {
    leading = !!options.leading;
    maxing = 'maxWait' in options;
    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
    trailing = 'trailing' in options ? !!options.trailing : trailing;
  }
  function invokeFunc (time) {
    let args = lastArgs;
    let thisArg = lastThis;
    lastArgs = lastThis = undefined;
    lastInvokeTime = time;
    result = func.apply(thisArg, args);
    return result
  }
  function leadingEdge (time) {
    lastInvokeTime = time;
    timerId = setTimeout(timerExpired, wait);
    return leading ? invokeFunc(time) : result
  }
  function remainingWait (time) {
    let timeSinceLastCall = time - lastCallTime;
    let timeSinceLastInvoke = time - lastInvokeTime;
    let timeWaiting = wait - timeSinceLastCall;
    return maxing
      ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
      : timeWaiting
  }
  function shouldInvoke (time) {
    let timeSinceLastCall = time - lastCallTime;
    let timeSinceLastInvoke = time - lastInvokeTime;
    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
  }
  function timerExpired () {
    let time = now();
    if (shouldInvoke(time)) {
      return trailingEdge(time)
    }
    timerId = setTimeout(timerExpired, remainingWait(time));
  }
  function trailingEdge (time) {
    timerId = undefined;
    if (trailing && lastArgs) {
      return invokeFunc(time)
    }
    lastArgs = lastThis = undefined;
    return result
  }
  function cancel () {
    if (timerId !== undefined) {
      clearTimeout(timerId);
    }
    lastInvokeTime = 0;
    lastArgs = lastCallTime = lastThis = timerId = undefined;
  }
  function flush () {
    return timerId === undefined ? result : trailingEdge(now())
  }
  function debounced () {
    let time = now();
    let isInvoking = shouldInvoke(time);
    lastArgs = arguments;
    lastThis = this;
    lastCallTime = time;
    if (isInvoking) {
      if (timerId === undefined) {
        return leadingEdge(lastCallTime)
      }
      if (maxing) {
        clearTimeout(timerId);
        timerId = setTimeout(timerExpired, wait);
        return invokeFunc(lastCallTime)
      }
    }
    if (timerId === undefined) {
      timerId = setTimeout(timerExpired, wait);
    }
    return result
  }
  debounced.cancel = cancel;
  debounced.flush = flush;
  return debounced
}
function throttle (func, wait, options) {
  let leading = true;
  let trailing = true;
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function')
  }
  if (isObject(options)) {
    leading = 'leading' in options ? !!options.leading : leading;
    trailing = 'trailing' in options ? !!options.trailing : trailing;
  }
  return debounce(func, wait, {
    'leading': leading,
    'maxWait': wait,
    'trailing': trailing
  })
}
原文地址:https://www.cnblogs.com/QQPrincekin/p/12456646.html