| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- //#region src/index.ts
- const DEBOUNCE_DEFAULTS = { trailing: true };
- /**
- Debounce functions
- @param fn - Promise-returning/async function to debounce.
- @param wait - Milliseconds to wait before calling `fn`. Default value is 25ms
- @returns A function that delays calling `fn` until after `wait` milliseconds have elapsed since the last time it was called.
- @example
- ```
- import { debounce } from 'perfect-debounce';
- const expensiveCall = async input => input;
- const debouncedFn = debounce(expensiveCall, 200);
- for (const number of [1, 2, 3]) {
- console.log(await debouncedFn(number));
- }
- //=> 1
- //=> 2
- //=> 3
- ```
- */
- function debounce(fn, wait = 25, options = {}) {
- options = {
- ...DEBOUNCE_DEFAULTS,
- ...options
- };
- if (!Number.isFinite(wait)) throw new TypeError("Expected `wait` to be a finite number");
- let leadingValue;
- let timeout;
- let resolveList = [];
- let currentPromise;
- let trailingArgs;
- const applyFn = (_this, args) => {
- currentPromise = _applyPromised(fn, _this, args);
- currentPromise.finally(() => {
- currentPromise = null;
- if (options.trailing && trailingArgs && !timeout) {
- const promise = applyFn(_this, trailingArgs);
- trailingArgs = null;
- return promise;
- }
- });
- return currentPromise;
- };
- const debounced = function(...args) {
- if (options.trailing) trailingArgs = args;
- if (currentPromise) return currentPromise;
- return new Promise((resolve) => {
- const shouldCallNow = !timeout && options.leading;
- clearTimeout(timeout);
- timeout = setTimeout(() => {
- timeout = null;
- const promise = options.leading ? leadingValue : applyFn(this, args);
- trailingArgs = null;
- for (const _resolve of resolveList) _resolve(promise);
- resolveList = [];
- }, wait);
- if (shouldCallNow) {
- leadingValue = applyFn(this, args);
- resolve(leadingValue);
- } else resolveList.push(resolve);
- });
- };
- const _clearTimeout = (timer) => {
- if (timer) {
- clearTimeout(timer);
- timeout = null;
- }
- };
- debounced.isPending = () => !!timeout;
- debounced.cancel = () => {
- _clearTimeout(timeout);
- resolveList = [];
- trailingArgs = null;
- };
- debounced.flush = () => {
- _clearTimeout(timeout);
- if (!trailingArgs || currentPromise) return;
- const args = trailingArgs;
- trailingArgs = null;
- return applyFn(this, args);
- };
- return debounced;
- }
- async function _applyPromised(fn, _this, args) {
- return await fn.apply(_this, args);
- }
- //#endregion
- export { debounce };
|