uchill/front_material/utils/performance.ts

143 lines
3.7 KiB
TypeScript

/**
* Утилиты для мониторинга и оптимизации производительности
*/
/**
* Измерение времени выполнения функции
*/
export function measurePerformance<T>(
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<T>(
fn: () => Promise<T>,
label?: string
): Promise<T> {
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<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout | null = null;
return function executedFunction(...args: Parameters<T>) {
const later = () => {
timeout = null;
func(...args);
};
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
};
}
/**
* Throttle функция для ограничения частоты вызовов
*/
export function throttle<T extends (...args: any[]) => any>(
func: T,
limit: number
): (...args: Parameters<T>) => void {
let inThrottle: boolean;
return function executedFunction(...args: Parameters<T>) {
if (!inThrottle) {
func(...args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
/**
* Проверка поддержки WebP
*/
export function supportsWebP(): Promise<boolean> {
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);
}