seitu
Version:
51 lines (50 loc) • 1.32 kB
JavaScript
import { createReadableSubscription, createSubscription } from "../subscription/index.mjs";
//#region src/core/debounced-fn/index.ts
/**
* Debounced callable that is also a subscribable. Each call resets the timer;
* the return value becomes the current state.
*
* @example
* ```ts twoslash
* import { createDebouncedFn } from 'seitu'
*
* const search = createDebouncedFn((query: string) => fetch(`/api?q=${query}`), 300)
* search.subscribe(result => console.log('result:', result))
* search('hello') // debounced — fires after 300ms of inactivity
* search.get()
* search.flush()
* search.cancel()
* ```
*/
function createDebouncedFn(fn, wait) {
let state;
let timeoutId;
let pendingArgs;
const { subscribe, notify } = createSubscription();
const get = () => state;
const cancel = () => {
clearTimeout(timeoutId);
timeoutId = void 0;
pendingArgs = void 0;
};
const run = () => {
const args = pendingArgs;
cancel();
state = fn(...args);
notify();
};
const flush = () => {
if (timeoutId !== void 0) run();
};
return Object.assign((...args) => {
clearTimeout(timeoutId);
pendingArgs = args;
timeoutId = setTimeout(run, wait);
}, createReadableSubscription(get, subscribe, notify), {
cancel,
flush,
pending: () => timeoutId !== void 0
});
}
//#endregion
export { createDebouncedFn };