Skip to content

Instantly share code, notes, and snippets.

@rendall
Last active July 20, 2023 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rendall/79a8559ad1b5a022a7923f160f7c429b to your computer and use it in GitHub Desktop.
Save rendall/79a8559ad1b5a022a7923f160f7c429b to your computer and use it in GitHub Desktop.
/**
* Creates a debounced function that delays invoking the provided
* function until after `wait` milliseconds have elapsed since the
* last time the debounced function was invoked. Typically used to
* run an expensive or async function after user interaction.
*
* @template T The type of the function to debounce.
* @param {T} func The function to debounce.
* @param {number} [wait=250] The number of milliseconds to delay.
* @returns {(...args: Parameters<T>) => void} Returns the new debounced function.
*
* @example
* // Usage with a function that takes one string parameter
* const logMessage = (message: string) => console.log(message);
* const debouncedLogMessage = debounceFunc(logMessage, 300);
* debouncedLogMessage('Hello, world!');
*/
export const debounceFunc = <T extends (...args: unknown[]) => unknown>(
func: T,
wait = 250
) => {
let debounceTimeout: number | null = null
return (...args: Parameters<T>): void => {
if (debounceTimeout) {
window.clearTimeout(debounceTimeout)
}
debounceTimeout = window.setTimeout(() => {
func(...args)
}, wait)
}
}
/*
// JavaScript
var debounceFunc = function (func, wait) {
if (wait === void 0) { wait = 250; }
var debounceTimeout = null;
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (debounceTimeout) {
window.clearTimeout(debounceTimeout);
}
debounceTimeout = window.setTimeout(function () {
func.apply(void 0, args);
}, wait);
};
};
// Use
const debounceQuery = debounceFunc(sendQuery, 250);
// <input onchange=debounceQuery />
// Tests:
describe("debounce", () => {
it("calls as expected", function (done) {
const callingArgument = "debounce it!"
const debounceCallback = (value: string) => {
expect(value).toBe(callingArgument)
done()
}
const debounce = debounceFunc(debounceCallback)
debounce(callingArgument)
})
it("does not call immediately", function (done) {
const startTime = new Date()
const debounceCallback = () => {
const duration = new Date().valueOf() - startTime.valueOf()
expect(duration).toBeGreaterThan(200)
done()
}
const debounce = debounceFunc(debounceCallback)
debounce("")
})
it("never calls callback if continuously called", function (done) {
let numCalls = 0
const debounceCallback = () => {
numCalls++
}
const debounce = debounceFunc(debounceCallback)
const testInterval = window.setInterval(() => debounce(""), 50)
const endTest = (toclear: number) => () => {
clearInterval(toclear)
expect(numCalls).toBe(0)
done()
}
setTimeout(endTest(testInterval), 500)
})
it("calls after its wait time", function (done) {
const waitTime = 1000
const startTime = new Date().valueOf()
expect.assertions(1)
const debounceCallback = () => {
const callTime = new Date().valueOf()
expect(callTime - startTime).toBeGreaterThanOrEqual(waitTime)
done()
}
const debounce = debounceFunc(debounceCallback, waitTime)
debounce("")
})
it("calls once only after debounce ends", function (done) {
let numCalls = 0
const debounceCallback = () => {
numCalls++
}
const debounce = debounceFunc(debounceCallback)
const testInterval = window.setInterval(() => debounce(""), 50)
const endInterval = (toclear: number) => () => {
clearInterval(toclear)
}
const endTest = () => {
expect(numCalls).toBe(1)
done()
}
setTimeout(endInterval(testInterval), 200)
setTimeout(endTest, 500)
})
})
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment