Last active
May 7, 2024 09:44
-
-
Save Yawenina/390e29db9dd16bf87ad7623959e61543 to your computer and use it in GitHub Desktop.
lodash debounce and throttle source code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const nativeMax = Math.max; | |
const nativeMin = Math.min; | |
function debounce(func, wait, options) { | |
let lastArgs, | |
lastThis, | |
maxWait, | |
result, | |
timerId, | |
lastCallTime, | |
lastInvokeTime = 0, | |
leading = false, | |
maxing = false, | |
trailing = true; | |
if (typeof func !== 'function') { | |
throw new TypeError(FUNC_ERROR_TEXT); | |
} | |
wait = Number(wait) || 0; | |
if (typeof options === 'object') { | |
leading = !!options.leading; | |
maxing = 'maxWait' in options; | |
maxWait = maxing | |
? nativeMax(Number(options.maxWait) || 0, wait) | |
: maxWait; | |
trailing = 'trailing' in options | |
? !!options.trailing | |
: trailing; | |
} | |
function invokeFunc(time) { | |
let args = lastArgs, | |
thisArg = lastThis; | |
lastArgs = lastThis = undefined; | |
lastInvokeTime = time; | |
result = func.apply(thisArg, args); | |
return result; | |
} | |
function leadingEdge(time) { | |
// Reset any `maxWait` timer. | |
lastInvokeTime = time; | |
// Start the timer for the trailing edge. | |
timerId = setTimeout(timerExpired, wait); | |
// Invoke the leading edge. | |
return leading | |
? invokeFunc(time) | |
: result; | |
} | |
function remainingWait(time) { | |
let timeSinceLastCall = time - lastCallTime, | |
timeSinceLastInvoke = time - lastInvokeTime, | |
result = wait - timeSinceLastCall; | |
console.log('remainingWait'); | |
return maxing | |
? nativeMin(result, maxWait - timeSinceLastInvoke) | |
: result; | |
} | |
function shouldInvoke(time) { | |
let timeSinceLastCall = time - lastCallTime, | |
timeSinceLastInvoke = time - lastInvokeTime; | |
// Either this is the first call, activity has stopped and we're at the trailing | |
// edge, the system time has gone backwards and we're treating it as the | |
// trailing edge, or we've hit the `maxWait` limit. | |
return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); | |
} | |
function timerExpired() { | |
const time = Date.now(); | |
if (shouldInvoke(time)) { | |
return trailingEdge(time); | |
} | |
// Restart the timer. | |
timerId = setTimeout(timerExpired, remainingWait(time)); | |
} | |
function trailingEdge(time) { | |
timerId = undefined; | |
// Only invoke if we have `lastArgs` which means `func` has been debounced at | |
// least once. | |
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() { | |
let time = Date.now(), | |
isInvoking = shouldInvoke(time); | |
lastArgs = arguments; | |
lastThis = this; | |
lastCallTime = time; | |
if (isInvoking) { | |
if (timerId === undefined) { | |
return leadingEdge(lastCallTime); | |
} | |
if (maxing) { | |
// Handle invocations in a tight loop. | |
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, | |
trailing = true; | |
if (typeof func !== 'function') { | |
throw new TypeError(FUNC_ERROR_TEXT); | |
} | |
if (typeof options === 'object') { | |
leading = 'leading' in options | |
? !!options.leading | |
: leading; | |
trailing = 'trailing' in options | |
? !!options.trailing | |
: trailing; | |
} | |
return debounce(func, wait, { | |
leading, | |
maxWait: wait, | |
trailing, | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment