143 lines
3.7 KiB
TypeScript
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);
|
|
}
|