Skip to content

Commit

Permalink
Update imports and remove fn-opts.test.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
shtse8 committed Mar 17, 2024
1 parent 01d0d01 commit a2b713b
Show file tree
Hide file tree
Showing 4 changed files with 438 additions and 52 deletions.
111 changes: 98 additions & 13 deletions src/fn-ops.ts → src/func.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,41 +94,126 @@ export function xor<Args extends readonly unknown[]>(...fns: Array<(...args: Arg
* Throttles a function.
* @param fn function to throttle
* @param ms time in milliseconds to throttle the function
* @param options options to configure the throttle
* @param options.leading whether to run the function on the leading edge
* @param options.trailing whether to run the function on the trailing edge
* @returns a throttled function
* @example
* const log = throttle(console.log, 1000)
* log('foo') // logs 'foo'
* log('bar') // does not log 'bar'
* log('baz') // does not log 'baz'
* setTimeout(() => log('qux'), 1000) // logs 'qux' after 1 second
*
* @example
* const log = throttle(console.log, 1000, { leading: false, trailing: true })
* log('foo') // does not log 'foo'
* log('bar') // does not log 'bar'
* log('baz') // does not log 'baz'
* setTimeout(() => log('qux'), 1000) // logs 'qux' after 1 second
*
* @example
* const log = throttle(console.log, 1000, { leading: true, trailing: false })
* log('foo') // logs 'foo'
* log('bar') // does not log 'bar'
* log('baz') // does not log 'baz'
* setTimeout(() => log('qux'), 1000) // does not log 'qux'
*
* @example
* const log = throttle(console.log, 1000, { leading: false, trailing: false })
* log('foo') // does not log 'foo'
* log('bar') // does not log 'bar'
* log('baz') // does not log 'baz'
* setTimeout(() => log('qux'), 1000) // does not log 'qux'
*
*/
export function throttle<Args extends readonly unknown[]>(fn: (...args: Args) => void, ms: number) {
let last = 0;
return (...args: Args) => {
const now = Date.now();
if (now - last < ms) return;
last = now;
export function throttle<Args extends readonly unknown[]>(fn: (...args: Args) => void, ms: number, { leading = true, trailing = true } = {}) {
let lastCallTime: number | null = null;
let lastInvokeTime: number = 0;
let timerId: ReturnType<typeof setTimeout> | null = null;
let lastArgs: Args | null = null;

const invoke = (args: Args) => {
lastInvokeTime = Date.now();
fn(...args);
}
};

const startTimer = (args: Args) => {
if (timerId !== null) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
if (trailing && lastArgs !== null) {
invoke(lastArgs);
}
timerId = null;
lastArgs = null;
}, ms);
};

const shouldInvoke = (time: number) => {
if (lastCallTime === null) return true;
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
return (timeSinceLastCall >= ms) || (timeSinceLastInvoke >= ms);
};

return function (...args: Args) {
const now = Date.now();
const isInvoking = shouldInvoke(now);

lastArgs = args;
lastCallTime = now;

if (isInvoking) {
if (leading) {
invoke(args);
}
startTimer(args);
} else if (timerId === null && trailing) {
startTimer(args);
}
};
}


/**
* Debounces a function.
* @param fn function to debounce
* @param ms time in milliseconds to debounce the function
* @param options options to configure the debounce
* @param options.immediate whether to run the function immediately
* @returns a debounced function
* @example
* const log = debounce(console.log, 1000)
* log('foo') // logs 'foo' after 1 second
* log('bar') // logs 'bar' after 1 second, 'foo' is not logged
*
* @example
* const log = debounce(console.log, 1000, { immediate: true })
* log('foo') // logs 'foo'
* log('bar') // does not log 'bar'
* log('baz') // does not log 'baz'
* setTimeout(() => log('qux'), 1000) // logs 'qux' after 1 second
*/
export function debounce<Args extends readonly unknown[]>(fn: (...args: Args) => void, ms: number) {
let timeout: Timer;
return (...args: Args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), ms);
}
export function debounce<Args extends readonly unknown[]>(fn: (...args: Args) => void, ms: number, { immediate = false } = {}) {
let timeoutId: ReturnType<typeof setTimeout> | null = null;

return function (...args: Args) {
const callNow = immediate && timeoutId === null;
const later = () => {
timeoutId = null;
if (!immediate) fn(...args);
};

if (timeoutId !== null) {
clearTimeout(timeoutId);
}

timeoutId = setTimeout(later, ms);

if (callNow) fn(...args);
};
}


Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

export * from './typed'
export * from './types'
export * from './fn-ops'
export * from './func'
export * from './str'
export * from './misc'
export * from './array'
Expand All @@ -11,7 +11,7 @@ export * from './object'

import * as typed from './typed'
import * as types from './types'
import * as fnOps from './fn-ops'
import * as fnOps from './func'
import * as str from './str'
import * as misc from './misc'
import * as array from './array'
Expand Down
37 changes: 0 additions & 37 deletions tests/fn-opts.test.ts

This file was deleted.

Loading

0 comments on commit a2b713b

Please sign in to comment.