my-utils-kit
Version:
A lightweight and type-safe utility library for working with strings, objects, array Performance methods in TypeScript. Includes helpful methods for deep cloning, object transformations, safe access, query string handling, and more — designed for modern J
182 lines (181 loc) • 5.54 kB
JavaScript
export function debounce(fn, delay, immediate = false) {
let timeout;
return function (...args) {
const context = this;
const callNow = immediate && !timeout;
if (timeout)
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
if (!immediate)
fn.apply(context, args);
}, delay);
if (callNow)
fn.apply(context, args);
};
}
export function throttle(fn, delay, immediate = false) {
let timer = null;
let lastArgs = null;
return function (...args) {
const context = this;
if (!timer) {
if (immediate) {
fn.apply(context, args);
}
else {
lastArgs = args;
}
timer = setTimeout(() => {
if (!immediate && lastArgs) {
fn.apply(context, lastArgs);
lastArgs = null;
}
timer = null;
}, delay);
}
};
}
export function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("Returning from cache:", key);
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
console.log("Calculating new result:", key);
return result;
};
}
export const asyncMemoize = async (fn) => {
const cache = new Map();
return async function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = await fn(...args);
cache.set(key, result);
return result;
};
};
export class OperationBatcher {
constructor() {
this.operations = [];
this.executing = false;
}
enqueueOperation(fn) {
this.operations.push(fn);
if (!this.executing) {
this.execute();
}
}
async execute() {
this.executing = true;
while (this.operations.length > 0) {
const operation = this.operations.shift();
if (operation) {
try {
await operation();
}
catch (err) {
console.error("Operation failed", err);
}
}
}
this.executing = false;
}
}
export function runCallbackOnUserEvent(callback, options) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const { events = ["mousemove", "scroll", "touchstart"], timeout } = options || {};
let executed = false;
function runOnce() {
if (executed)
return;
executed = true;
for (const event of events) {
document.removeEventListener(event, runOnce);
}
callback();
}
for (const event of events) {
document.addEventListener(event, runOnce, { once: true, passive: true });
}
if (typeof timeout === "number" && timeout > 0) {
setTimeout(runOnce, timeout);
}
}
export function loadScriptOnUserEvent(src, options) {
if (typeof src !== "string" || !src.trim()) {
throw new Error("Script source must be a non-empty string");
}
const { events = ["mousemove", "scroll", "touchstart"], timeout } = options || {};
let executed = false;
function loadScript() {
if (executed)
return;
executed = true;
for (const event of events) {
document.removeEventListener(event, loadScript);
}
const script = document.createElement("script");
script.src = src;
script.async = true;
document.head.appendChild(script);
}
for (const event of events) {
document.addEventListener(event, loadScript, { once: true, passive: true });
}
if (typeof timeout === "number" && timeout > 0) {
setTimeout(loadScript, timeout);
}
}
export function observeElementOnIntersect(selector, options, callback) {
if (typeof selector !== "string") {
throw new Error("Selector must be a string");
}
const elements = document.querySelectorAll(selector);
if (!elements.length)
return;
const observer = new IntersectionObserver((entries, obs) => {
for (const entry of entries) {
if (entry.isIntersecting) {
callback(entry);
obs.unobserve(entry.target);
}
}
}, options);
elements.forEach((el) => observer.observe(el));
}
export function getScreenSize(ranges = {
xs: { min: 0, max: 480 },
sm: { min: 481, max: 640 },
md: { min: 641, max: 768 },
lg: { min: 769, max: 1024 },
xl: { min: 1025, max: 1280 },
"2xl": { min: 1281, max: 1536 },
"3xl": { min: 1537, max: Infinity }
}) {
const width = window.innerWidth;
for (const [label, { min, max }] of Object.entries(ranges)) {
if (width >= min && width <= max) {
return label;
}
}
return undefined; // fallback
}
export function watchScreenSize(callback, ranges) {
function handler() {
const size = getScreenSize(ranges || undefined);
callback(size);
}
window.addEventListener('resize', handler);
handler(); // Call immediately on setup
return () => window.removeEventListener('resize', handler);
}