update
This commit is contained in:
152
ts/dettle/debounce.ts
Normal file
152
ts/dettle/debounce.ts
Normal file
@ -0,0 +1,152 @@
|
||||
|
||||
/* IMPORT */
|
||||
|
||||
import type {FN, Debounced} from './types.js';
|
||||
|
||||
/* MAIN */
|
||||
|
||||
const debounce = <Args extends unknown[]> ( fn: FN<Args, unknown>, wait: number = 1, options?: { leading?: boolean, trailing?: boolean, maxWait?: number } ): Debounced<Args> => {
|
||||
|
||||
/* VARIABLES */
|
||||
|
||||
wait = Math.max ( 1, wait );
|
||||
|
||||
const leading = options?.leading ?? false;
|
||||
const trailing = options?.trailing ?? true;
|
||||
const maxWait = Math.max ( options?.maxWait ?? Infinity, wait );
|
||||
|
||||
let args: Args | undefined;
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
let timestampCall = 0;
|
||||
let timestampInvoke = 0;
|
||||
|
||||
/* HELPERS */
|
||||
|
||||
const getInstantData = (): [number, boolean] => {
|
||||
|
||||
const timestamp = Date.now ();
|
||||
const elapsedCall = timestamp - timestampCall;
|
||||
const elapsedInvoke = timestamp - timestampInvoke;
|
||||
const isInvoke = ( elapsedCall >= wait || elapsedInvoke >= maxWait );
|
||||
|
||||
return [timestamp, isInvoke];
|
||||
|
||||
};
|
||||
|
||||
const invoke = ( timestamp: number ): void => {
|
||||
|
||||
timestampInvoke = timestamp;
|
||||
|
||||
if ( !args ) return; // This should never happen
|
||||
|
||||
const _args = args;
|
||||
|
||||
args = undefined;
|
||||
|
||||
fn.apply ( undefined, _args );
|
||||
|
||||
};
|
||||
|
||||
const onCancel = (): void => {
|
||||
|
||||
resetTimeout ( 0 );
|
||||
|
||||
};
|
||||
|
||||
const onFlush = (): void => {
|
||||
|
||||
if ( !timeout ) return;
|
||||
|
||||
onCancel ();
|
||||
|
||||
invoke ( Date.now () );
|
||||
|
||||
};
|
||||
|
||||
const onLeading = ( timestamp: number ): void => {
|
||||
|
||||
timestampInvoke = timestamp;
|
||||
|
||||
if ( leading ) return invoke ( timestamp );
|
||||
|
||||
};
|
||||
|
||||
const onTrailing = ( timestamp: number ): void => {
|
||||
|
||||
if ( trailing && args ) return invoke ( timestamp );
|
||||
|
||||
args = undefined;
|
||||
|
||||
};
|
||||
|
||||
const onTimeout = (): void => {
|
||||
|
||||
timeout = undefined;
|
||||
|
||||
const [timestamp, isInvoking] = getInstantData ();
|
||||
|
||||
if ( isInvoking ) return onTrailing ( timestamp );
|
||||
|
||||
return updateTimeout ( timestamp );
|
||||
|
||||
};
|
||||
|
||||
const updateTimeout = ( timestamp: number ): void => {
|
||||
|
||||
const elapsedCall = timestamp - timestampCall;
|
||||
const elapsedInvoke = timestamp - timestampInvoke;
|
||||
const remainingCall = wait - elapsedCall;
|
||||
const remainingInvoke = maxWait - elapsedInvoke;
|
||||
const ms = Math.min ( remainingCall, remainingInvoke );
|
||||
|
||||
return resetTimeout ( ms );
|
||||
|
||||
};
|
||||
|
||||
const resetTimeout = ( ms: number ): void => {
|
||||
|
||||
if ( timeout ) clearTimeout ( timeout );
|
||||
|
||||
if ( ms <= 0 ) return;
|
||||
|
||||
timeout = setTimeout ( onTimeout, ms );
|
||||
|
||||
};
|
||||
|
||||
/* DEBOUNCED */
|
||||
|
||||
const debounced = ( ...argsLatest: Args ): void => {
|
||||
|
||||
const [timestamp, isInvoking] = getInstantData ();
|
||||
const hadTimeout = !!timeout;
|
||||
|
||||
args = argsLatest;
|
||||
timestampCall = timestamp;
|
||||
|
||||
if ( isInvoking || !timeout ) resetTimeout ( wait );
|
||||
|
||||
if ( isInvoking ) {
|
||||
|
||||
if ( !hadTimeout ) return onLeading ( timestamp );
|
||||
|
||||
return invoke ( timestamp );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* DEBOUNCED UTILITIES */
|
||||
|
||||
debounced.cancel = onCancel;
|
||||
|
||||
debounced.flush = onFlush;
|
||||
|
||||
/* RETURN */
|
||||
|
||||
return debounced;
|
||||
|
||||
};
|
||||
|
||||
/* EXPORT */
|
||||
|
||||
export default debounce;
|
9
ts/dettle/index.ts
Executable file
9
ts/dettle/index.ts
Executable file
@ -0,0 +1,9 @@
|
||||
|
||||
/* IMPORT */
|
||||
|
||||
import debounce from './debounce.js';
|
||||
import throttle from './throttle.js';
|
||||
|
||||
/* EXPORT */
|
||||
|
||||
export {debounce, throttle};
|
21
ts/dettle/license
Normal file
21
ts/dettle/license
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023-present Fabio Spampinato
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
21
ts/dettle/throttle.ts
Normal file
21
ts/dettle/throttle.ts
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
/* IMPORT */
|
||||
|
||||
import debounce from './debounce.js';
|
||||
import type {FN, Throttled} from './types.js';
|
||||
|
||||
/* MAIN */
|
||||
|
||||
const throttle = <Args extends unknown[]> ( fn: FN<Args, unknown>, wait: number = 1, options?: { leading?: boolean, trailing?: boolean } ): Throttled<Args> => {
|
||||
|
||||
return debounce ( fn, wait, {
|
||||
maxWait: wait,
|
||||
leading: options?.leading ?? true,
|
||||
trailing: options?.trailing ?? true
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/* EXPORT */
|
||||
|
||||
export default throttle;
|
14
ts/dettle/types.ts
Normal file
14
ts/dettle/types.ts
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
/* MAIN */
|
||||
|
||||
type Callback = () => void;
|
||||
|
||||
type FN<Args extends unknown[], Return> = ( ...args: Args ) => Return;
|
||||
|
||||
type Debounced<Args extends unknown[]> = FN<Args, void> & { cancel: Callback, flush: Callback };
|
||||
|
||||
type Throttled<Args extends unknown[]> = FN<Args, void> & { cancel: Callback, flush: Callback };
|
||||
|
||||
/* EXPORT */
|
||||
|
||||
export type {Callback, FN, Debounced, Throttled};
|
Reference in New Issue
Block a user