const FUNC_ERROR_TEXT = 'Expected a function' const NAN = 0 / 0 const nativeMax = Math.max const nativeMin = Math.min const reIsBinary = /^0b[01]+$/i const reIsOctal = /^0o[0-7]+$/i const reIsBadHex = /^[-+]0x[0-9a-f]+$/i const freeParseInt = parseInt const reTrim = /^\s+|\s+$/g const symbolTag = '[object Symbol]' const undefinedTag = '[object Undefined]' const nullTag = '[object Null]' //const symToStringTag = Symbol ? Symbol.toStringTag : undefined const symToStringTag: typeof Symbol.toStringTag = Symbol ? Symbol.toStringTag : undefined! const objectProto = Object.prototype const hasOwnProperty = objectProto.hasOwnProperty const nativeObjectToString = objectProto.toString export function throttle(func: any, wait: any) { const leading = true const trailing = true if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT) } return debounce(func, wait, { leading: leading, maxWait: wait, trailing: trailing, }) } function isObject(value: any) { const type = typeof value return value != null && (type == 'object' || type == 'function') } function debounce(func: any, wait: any, options: any) { let lastArgs: any let lastThis: any let maxWait: any let result: any let timerId: any let lastCallTime: any let lastInvokeTime = 0 let leading = false let maxing = false let trailing = true if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT) } 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: any) { const args = lastArgs const thisArg = lastThis lastArgs = lastThis = undefined lastInvokeTime = time result = func.apply(thisArg, args) return result } function leadingEdge(time: any) { lastInvokeTime = time timerId = setTimeout(timerExpired, wait) return leading ? invokeFunc(time) : result } function remainingWait(time: any) { const timeSinceLastCall = time - lastCallTime const timeSinceLastInvoke = time - lastInvokeTime const timeWaiting = wait - timeSinceLastCall return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting } function shouldInvoke(time: any) { const timeSinceLastCall = time - lastCallTime const timeSinceLastInvoke = time - lastInvokeTime return ( lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxing && timeSinceLastInvoke >= maxWait) ) } function timerExpired() { const time = Date.now() if (shouldInvoke(time)) { return trailingEdge(time) } timerId = setTimeout(timerExpired, remainingWait(time)) } function trailingEdge(time: any) { 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(Date.now()) } function debounced(this: any, ...args: any[]) { const time = Date.now() const isInvoking = shouldInvoke(time) lastArgs = args // eslint-disable-next-line @typescript-eslint/no-this-alias 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 toNumber(value: any) { if (typeof value == 'number') { return value } if (isSymbol(value)) { return NAN } if (isObject(value)) { const 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, '') const isBinary = reIsBinary.test(value) return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value } function isSymbol(value: any) { return ( typeof value == 'symbol' || (isObjectLike(value) && baseGetTag(value) == symbolTag) ) } function isObjectLike(value: any) { return value != null && typeof value == 'object' } function baseGetTag(value: any) { if (value == null) { return value === undefined ? undefinedTag : nullTag } return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value) } function getRawTag(value: any) { const isOwn = hasOwnProperty.call(value, symToStringTag) const tag = value[symToStringTag] const unmasked = true try { value[symToStringTag] = undefined const unmasked = true } catch (e) { console.log(e) } const result = nativeObjectToString.call(value) if (unmasked) { if (isOwn) { value[symToStringTag] = tag } else { delete value[symToStringTag] } } return result } function objectToString(value: any) { return nativeObjectToString.call(value) }