Last active
May 31, 2022 23:22
-
-
Save MichaelGitArt/6eb455e064b7ec33ddfff9f686b1aafc to your computer and use it in GitHub Desktop.
This file contains 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
Throttle execution of a function. Especially useful for rate limiting execution of handlers on events like resize and scroll. |
This file contains 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
/* eslint-disable no-undefined,no-param-reassign,no-shadow */ | |
/** | |
* Throttle execution of a function. Especially useful for rate limiting | |
* execution of handlers on events like resize and scroll. | |
* | |
* @param {Function} callback - A function to be executed after delay milliseconds. The `this` context and all arguments are passed through, | |
* as-is, to `callback` when the throttled-function is executed. | |
* | |
* @param {number} delay - A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) | |
* are most useful. | |
* | |
* @param {object} [options] - An object to configure options. | |
* @param {boolean} [options.noTrailing] - Optional, defaults to false. If noTrailing is true, callback will only execute every `delay` milliseconds | |
* while the throttled-function is being called. If noTrailing is false or unspecified, callback will be executed | |
* one final time after the last throttled-function call. (After the throttled-function has not been called for | |
* `delay` milliseconds, the internal counter is reset). | |
* @param {boolean} [options.noLeading] - Optional, defaults to false. If noLeading is false, the first throttled-function call will execute callback | |
* immediately. If noLeading is true, the first the callback execution will be skipped. It should be noted that | |
* callback will never executed if both noLeading = true and noTrailing = true. | |
* @param {boolean} [options.debounceMode] - If `debounceMode` is true (at begin), schedule `clear` to execute after `delay` ms. If `debounceMode` is | |
* false (at end), schedule `callback` to execute after `delay` ms. | |
* | |
* @returns {Function} A new, throttled, function. | |
*/ | |
export const useThrottle = function(callback, delay, options) { | |
const { | |
noTrailing = false, | |
noLeading = false, | |
debounceMode = undefined, | |
} = options || {} | |
let timeoutID | |
let cancelled = false | |
// Keep track of the last time `callback` was executed. | |
let lastExec = 0 | |
// Function to clear existing timeout | |
function clearExistingTimeout() { | |
if (timeoutID) | |
clearTimeout(timeoutID) | |
} | |
// Function to cancel next exec | |
function cancel(options) { | |
const { upcomingOnly = false } = options || {} | |
clearExistingTimeout() | |
cancelled = !upcomingOnly | |
} | |
function wrapper(...arguments_) { | |
// eslint-disable-next-line @typescript-eslint/no-this-alias | |
const self = this | |
const elapsed = Date.now() - lastExec | |
if (cancelled) | |
return | |
// Execute `callback` and update the `lastExec` timestamp. | |
function exec() { | |
lastExec = Date.now() | |
callback.apply(self, arguments_) | |
} | |
function clear() { | |
timeoutID = undefined | |
} | |
if (!noLeading && debounceMode && !timeoutID) | |
exec() | |
clearExistingTimeout() | |
if (debounceMode === undefined && elapsed > delay) { | |
if (noLeading) { | |
lastExec = Date.now() | |
if (!noTrailing) | |
timeoutID = setTimeout(debounceMode ? clear : exec, delay) | |
} | |
else { | |
exec() | |
} | |
} | |
else if (noTrailing !== true) { | |
timeoutID = setTimeout( | |
debounceMode ? clear : exec, | |
debounceMode === undefined ? delay - elapsed : delay, | |
) | |
} | |
} | |
wrapper.cancel = cancel | |
// Return the wrapper function. | |
return wrapper | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment