/** * Утилиты для мониторинга и оптимизации производительности */ /** * Измерение времени выполнения функции */ export function measurePerformance( fn: () => T, label?: string ): T { if (process.env.NODE_ENV === 'development') { const start = performance.now(); const result = fn(); const end = performance.now(); console.log(`[Performance] ${label || 'Function'} took ${(end - start).toFixed(2)}ms`); return result; } return fn(); } /** * Асинхронное измерение времени выполнения функции */ export async function measureAsyncPerformance( fn: () => Promise, label?: string ): Promise { if (process.env.NODE_ENV === 'development') { const start = performance.now(); const result = await fn(); const end = performance.now(); console.log(`[Performance] ${label || 'Async function'} took ${(end - start).toFixed(2)}ms`); return result; } return fn(); } /** * Debounce функция для оптимизации частых вызовов */ export function debounce any>( func: T, wait: number ): (...args: Parameters) => void { let timeout: NodeJS.Timeout | null = null; return function executedFunction(...args: Parameters) { const later = () => { timeout = null; func(...args); }; if (timeout) { clearTimeout(timeout); } timeout = setTimeout(later, wait); }; } /** * Throttle функция для ограничения частоты вызовов */ export function throttle any>( func: T, limit: number ): (...args: Parameters) => void { let inThrottle: boolean; return function executedFunction(...args: Parameters) { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; } /** * Проверка поддержки WebP */ export function supportsWebP(): Promise { return new Promise((resolve) => { const webP = new Image(); webP.onload = webP.onerror = () => { resolve(webP.height === 2); }; webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA'; }); } /** * Lazy load изображений */ export function lazyLoadImages() { if (typeof window === 'undefined' || !('IntersectionObserver' in window)) { return; } const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { const img = entry.target as HTMLImageElement; if (img.dataset.src) { img.src = img.dataset.src; img.removeAttribute('data-src'); } observer.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach((img) => { imageObserver.observe(img); }); } /** * Preload критических ресурсов */ export function preloadResource(href: string, as: string) { if (typeof document === 'undefined') return; const link = document.createElement('link'); link.rel = 'preload'; link.href = href; link.as = as; document.head.appendChild(link); } /** * Prefetch ресурсов для следующей страницы */ export function prefetchResource(href: string) { if (typeof document === 'undefined') return; const link = document.createElement('link'); link.rel = 'prefetch'; link.href = href; document.head.appendChild(link); }