/** * Performance Monitoring Utility * Wraps operations with console.time/timeEnd for development and production feature flag */ /** * Check if performance monitoring is enabled * @returns {boolean} */ export function isPerfMonitoringEnabled() { return ( import.meta.env.DEV || localStorage.getItem('enablePerfMonitoring') === 'true' ); } /** * Monitor performance of an operation * @param {string} label - Operation label * @param {Function} fn - Function to monitor * @returns {Promise|any} Result of the function */ export async function perfMonitor(label, fn) { if (!isPerfMonitoringEnabled()) { return typeof fn === 'function' ? await fn() : fn; } const perfLabel = `⚡ ${label}`; console.time(perfLabel); try { const result = typeof fn === 'function' ? await fn() : fn; console.timeEnd(perfLabel); return result; } catch (error) { console.timeEnd(perfLabel); console.error(`${perfLabel} failed:`, error); throw error; } } /** * Detect device performance characteristics * @returns {Object} Performance info */ export function getDevicePerformance() { const cores = navigator.hardwareConcurrency || 4; const memory = navigator.deviceMemory || 4; // GB return { cores, memory, isHighPerformance: cores >= 8 && memory >= 8, isMediumPerformance: cores >= 4 && memory >= 4, isLowPerformance: cores < 4 || memory < 4, recommendedChunkSize: cores >= 8 ? 1000 : cores >= 4 ? 500 : 250 }; } /** * Debounce function for performance optimization * @param {Function} fn - Function to debounce * @param {number} delay - Delay in milliseconds * @returns {Function} Debounced function */ export function debounce(fn, delay = 300) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn.apply(this, args), delay); }; } /** * Throttle function for performance optimization * @param {Function} fn - Function to throttle * @param {number} limit - Limit in milliseconds * @returns {Function} Throttled function */ export function throttle(fn, limit = 100) { let inThrottle; return function (...args) { if (!inThrottle) { fn.apply(this, args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }