Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const copied = await commonUtil.copyToClipboard("Hello, World!"); // true if suc
const encoded = commonUtil.encodeBase64("Hello 한글!"); // Base64 encoded string
const decoded = commonUtil.decodeBase64(encoded); // "Hello 한글!"
const debouncedFn = commonUtil.debounce(() => console.log("Called!"), 300); // Debounced function
const throttledFn = commonUtil.throttle(() => console.log("Throttled!"), 300); // Throttled function

// Storage
commonUtil.storage.set("user", { id: 1, name: "John" }); // Stores object in localStorage
Expand Down Expand Up @@ -180,6 +181,7 @@ storage.set("data", { key: "value" });
- `encodeBase64(str: string, options?: { convertSpecialChars?: boolean }): string` - Encodes a string to Base64 format with optional special character handling
- `decodeBase64(str: string, options?: { convertSpecialChars?: boolean }): string` - Decodes a Base64 string back to original text with optional special character handling
- `debounce<T>(fn: T, delay?: number): (...args: Parameters<T>) => void` - Creates a debounced function that delays execution until after a specified delay (default 300ms) has passed since its last invocation
- `throttle<T>(fn: T, limit?: number): (...args: Parameters<T>) => void` - Creates a throttled function that only executes at most once per specified time interval (default 300ms), ignoring subsequent calls within the limit
- `storage.set<T>(key: string, value: T): void` - Stores a value in localStorage with automatic JSON serialization. Supports objects, arrays, and primitive types. Safe for SSR environments.
- `storage.get<T>(key: string): T | null` - Retrieves a value from localStorage with automatic JSON parsing. Returns null if key doesn't exist or parsing fails. Type-safe with generic support.
- `storage.remove(key: string): void` - Removes a specific item from localStorage. Safe for SSR environments.
Expand Down
1 change: 1 addition & 0 deletions package/commonUtil/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export { default as copyToClipboard } from "./copyToClipboard";
export { default as encodeBase64 } from "./encodeBase64";
export { default as decodeBase64 } from "./decodeBase64";
export { default as debounce } from "./debounce";
export { default as throttle } from "./throttle";
export { default as storage } from "./storage";
41 changes: 41 additions & 0 deletions package/commonUtil/throttle/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { afterEach, describe, expect, test, vi } from "vitest";
import throttle from ".";

describe("throttle 유틸 함수 테스트", () => {
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
test("함수가 지정된 시간 (300ms) 간격으로만 실행되어야 한다.", () => {
const fn = vi.fn();
vi.useFakeTimers();
const throttleFn = throttle(fn, 300);

throttleFn();
expect(fn).toHaveBeenCalledTimes(1);

throttleFn();
vi.advanceTimersByTime(299);
throttleFn();
expect(fn).toHaveBeenCalledTimes(1);

vi.advanceTimersByTime(1);
throttleFn();
expect(fn).toHaveBeenCalledTimes(2);
});
test("여러 번 호출했을 경우에는 지정된 시간 간격으로만 이벤트가 실행되어야 한다.", () => {
const fn = vi.fn();
vi.useFakeTimers();
const throttled = throttle(fn, 300);

throttled({ name: "현우" });
vi.advanceTimersByTime(100);
throttled({ name: "승준" });
vi.advanceTimersByTime(100);
throttled({ name: "철수" });

vi.advanceTimersByTime(300);
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenNthCalledWith(1, { name: "현우" });
});
});
13 changes: 13 additions & 0 deletions package/commonUtil/throttle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default function throttle<T extends (...args: unknown[]) => void>(
fn: T,
limit: number = 300
) {
let isThrottled: boolean = false;
return (...args: Parameters<T>) => {
if (!isThrottled) {
fn(...args);
isThrottled = true;
setTimeout(() => (isThrottled = false), limit);
}
};
}