Last active
July 30, 2024 07:01
-
-
Save carlhannes/4b318c28e95f635191bffb656b9a2cfe to your computer and use it in GitHub Desktop.
ES6 Async Debounce JavaScript & TypeScript Helper Functions
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
// ES6 Async version of the "classic" JavaScript Debounce function. | |
// Works both with and without promises, so you can replace your existing | |
// debounce helper function with this one (and it will behave the same). | |
// The only difference is that this one returns a promise, so you can use | |
// it with async/await. | |
// | |
// I've converted this into a TypeScript module, and added a few more | |
// features to it, such as the ability to cancel the debounce, and also | |
// execute the function immediately, using the `doImmediately` method. | |
// | |
// Returns a function, that, as long as it continues to be invoked, will not | |
// be triggered. The function will be called after it stops being called for | |
// N milliseconds. If `immediate` is passed, trigger the function on the | |
// leading edge, instead of the trailing. | |
// | |
// @author: @carlhannes | |
// @param {Function} func - The function to debounce. | |
// @param {Number} wait - The number of milliseconds to delay. | |
// @param {Boolean} immediate - Whether to execute the function at the beginning. | |
// @returns {Function} - The debounced function. | |
// @example | |
// import debounce from 'utils/debounce'; | |
// | |
// const debounced = debounce(() => { | |
// console.log('Hello world!'); | |
// }, 1000); | |
// | |
// debounced(); | |
// | |
interface DebounceConstructor { | |
(func: () => void, wait: number, immediate?: boolean): DebouncedFunction; | |
} | |
interface DebouncedFunction { | |
(...args: unknown[]): Promise<unknown>; | |
cancel(): void; | |
doImmediately(...args: unknown[]): Promise<unknown>; | |
} | |
const debounce: DebounceConstructor = (func: () => void, wait: number, immediate?: boolean) => { | |
let timeout: NodeJS.Timeout | null = null; | |
const debouncedFn: DebouncedFunction = (...args) => new Promise((resolve) => { | |
clearTimeout(timeout); | |
timeout = setTimeout(() => { | |
timeout = null; | |
if (!immediate) { | |
void Promise.resolve(func.apply(this, [...args])).then(resolve); | |
} | |
}, wait); | |
if (immediate && !timeout) { | |
void Promise.resolve(func.apply(this, [...args])).then(resolve); | |
} | |
}); | |
debouncedFn.cancel = () => { | |
clearTimeout(timeout); | |
timeout = null; | |
}; | |
debouncedFn.doImmediately = (...args) => new Promise((resolve) => { | |
clearTimeout(timeout); | |
timeout = setTimeout(() => { | |
timeout = null; | |
void Promise.resolve(func.apply(this, [...args])).then(resolve); | |
}, 0); | |
}); | |
return debouncedFn; | |
}; | |
export default debounce; |
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
// ES6 Async version of the "classic" JavaScript Debounce function. | |
// Works both with and without promises, so you can replace your existing | |
// debounce helper function with this one (and it will behave the same). | |
// | |
// Returns a function, that, as long as it continues to be invoked, will not | |
// be triggered. The function will be called after it stops being called for | |
// N milliseconds. If `immediate` is passed, trigger the function on the | |
// leading edge, instead of the trailing. | |
// | |
export default function debounce (func, wait, immediate) { | |
let timeout | |
return function (...args) { | |
return new Promise((resolve) => { | |
clearTimeout(timeout) | |
timeout = setTimeout(() => { | |
timeout = null | |
if (!immediate) { | |
Promise.resolve(func.apply(this, [...args])).then(resolve) | |
} | |
}, wait) | |
if (immediate && !timeout) { | |
Promise.resolve(func.apply(this, [...args])).then(resolve) | |
} | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment