UNPKG

@ayonli/jsext

Version:

A JavaScript extension package for building strong and modern applications.

108 lines (107 loc) 3.39 kB
/** * Debounces function calls for frequent access. * @module */ /** * Options for the {@link debounce} function. */ export interface DebounceOptions { /** * The delay duration (in milliseconds) to wait before invoking the * handler function. */ delay: number; /** * Use the debounce strategy `for` the given key, this will keep the * debounce context in a global registry, binding new `handler` function * for the same key will override the previous settings. This mechanism * guarantees that both creating the debounced function in function * scopes and overwriting the handler are possible. */ for?: any; } /** * Creates a debounced function that delays invoking `handler` until after * `delay` duration (in milliseconds) have elapsed since the last time the * debounced function was invoked. * * If a subsequent call happens within the `delay` duration (in milliseconds), * the previous call will be canceled and it will result in the same return * value as the new call's. * * Optionally, we can provide a `reducer` function to merge data before * processing so multiple calls can be merged into one. * * @example * ```ts * import debounce from "@ayonli/jsext/debounce"; * import { sleep } from "@ayonli/jsext/async"; * * let count = 0; * * const fn = debounce((obj: { foo?: string; bar?: string }) => { * count++; * return obj; * }, 1_000); * * const [res1, res2] = await Promise.all([ * fn({ foo: "hello", bar: "world" }), * sleep(100).then(() => fn({ foo: "hi" })), * ]); * * console.log(res1); // { foo: "hi" } * console.log(res2); // { foo: "hi" } * console.log(count); // 1 * ``` * * @example * ```ts * // with reducer * import debounce from "@ayonli/jsext/debounce"; * * const fn = debounce((obj: { foo?: string; bar?: string }) => { * return obj; * }, 1_000, (prev, curr) => { * return { ...prev, ...curr }; * }); * * const [res1, res2] = await Promise.all([ * fn({ foo: "hello", bar: "world" }), * fn({ foo: "hi" }), * ]); * * console.log(res1); // { foo: "hi", bar: "world" } * console.assert(res2 === res1); * ``` */ export default function debounce<I, T, R>(handler: (this: I, data: T) => R | Promise<R>, delay: number, reducer?: (prev: T, current: T) => T): (this: I, data: T) => Promise<R>; /** * @example * ```ts * import debounce from "@ayonli/jsext/debounce"; * * const key = "unique_key" * let count = 0; * * const [res1, res2] = await Promise.all([ * debounce(async (obj: { foo?: string; bar?: string }) => { * count += 1; * return await Promise.resolve(obj); * }, { delay: 5, for: "foo" }, (prev, data) => { * return { ...prev, ...data }; * })({ foo: "hello", bar: "world" }), * * debounce(async (obj: { foo?: string; bar?: string }) => { * count += 2; * return await Promise.resolve(obj); * }, { delay: 5, for: "foo" }, (prev, data) => { * return { ...prev, ...data }; * })({ foo: "hi" }), * ]); * * console.log(res1); // { foo: "hi", bar: "world" } * console.assert(res1 === res2); * console.assert(count === 2); * ``` */ export default function debounce<I, T, R>(handler: (this: I, data: T) => R | Promise<R>, options: DebounceOptions, reducer?: (prev: T, current: T) => T): (this: I, data: T) => Promise<R>;