节流防抖
// 节流函数 (最后一次不执行) // 立即执行 在单位时间内只触发一次事件 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 }) }