Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: throttle function #483

Merged
merged 4 commits into from
Oct 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
"import": "./dist/lib/splitText.mjs",
"require": "./dist/lib/splitText.js"
},
"./throttle": {
"types": "./dist/lib/throttle.d.ts",
"import": "./dist/lib/throttle.mjs",
"require": "./dist/lib/throttle.js"
},
"./toTitleCase": {
"types": "./dist/lib/toTitleCase.d.ts",
"import": "./dist/lib/toTitleCase.mjs",
Expand Down
1 change: 1 addition & 0 deletions packages/utilities/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export * from './lib/regExpEsc';
export * from './lib/roundNumber';
export { sleep, sleepSync, AbortError, type SleepOptions } from './lib/sleep';
export * from './lib/splitText';
export { throttle, type ThrottleFn } from './lib/throttle';
export { toTitleCase, type ToTitleCaseOptions } from './lib/toTitleCase';
export * from './lib/tryParse';
export * from './lib/types';
33 changes: 33 additions & 0 deletions packages/utilities/src/lib/throttle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export type ThrottleFn<T extends (...args: any[]) => any> = T & { flush: () => void };

/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled function comes with a `flush` method to
* reset the last time the throttled function was invoked.
*
* @param func The function to throttle.
* @param wait The number of milliseconds to throttle invocations to.
*
* @returns Returns the new throttled function.
*/
export function throttle<T extends (...args: any[]) => any>(func: T, wait: number): ThrottleFn<T> {
let prev = 0;
let prevValue: ReturnType<T>;

return Object.assign(
(...args: Parameters<T>) => {
const now = Date.now();
if (now - prev > wait) {
prev = now;
return (prevValue = func(...args));
}

return prevValue;
},
{
flush() {
prev = 0;
}
}
) as ThrottleFn<T>;
}
26 changes: 26 additions & 0 deletions packages/utilities/tests/throttle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { throttle, sleep } from '../src';

describe('throttle', () => {
test('GIVEN number callback THEN returns the same output until the delay', async () => {
const callback = vi.fn((num: number) => num);

const throttleFunc = throttle(callback, 50);
const now = Date.now();
expect(throttleFunc(now)).toEqual(now);
expect(throttleFunc(100)).toEqual(now);
expect(callback).toHaveBeenCalledOnce();
await sleep(100);
expect(throttleFunc(250)).toEqual(250);
});

test('GIVEN number callback THEN returns the new output when flush', () => {
const callback = vi.fn((num: number) => num);

const throttleFunc = throttle(callback, 100);
const now = Date.now();
expect(throttleFunc(now)).toEqual(now);
throttleFunc.flush();
expect(throttleFunc(100)).toEqual(100);
expect(callback).toHaveBeenCalledTimes(2);
});
});