← Назад к вопросам
Как оптимизировать приложение с большим количеством изображений?
1.8 Middle🔥 112 комментариев
#JavaScript Core
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Оптимизация приложения с большим количеством изображений
Большое количество изображений может замедлить приложение. Я использую комплексный подход для решения этой проблемы.
1. Использование Next.js Image компонента
NextImage автоматически оптимизирует изображения с кешированием на CDN:
import Image from 'next/image';
function ProfileCard({ user }) {
return (
<Image
src={user.avatar}
alt={user.name}
width={200}
height={200}
priority={false} // lazy loading по умолчанию
quality={85} // баланс качества и размера
placeholder="blur" // blur до загрузки
blurDataURL="data:image/jpeg;base64,..."
/>
);
}
2. Ленивая загрузка (Lazy Loading)
Загружаем изображения только когда они видны в viewport:
function ImageGallery({ images }) {
const [visibleImages, setVisibleImages] = useState(new Set());
const observerRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setVisibleImages(prev => new Set(prev).add(entry.target.id));
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
document.querySelectorAll('.gallery-image').forEach(img => {
observer.observe(img);
});
return () => observer.disconnect();
}, []);
return (
<div className="gallery">
{images.map(img => (
<img
key={img.id}
id={img.id}
className="gallery-image"
src={visibleImages.has(img.id) ? img.url : ''}
alt={img.alt}
loading="lazy"
/>
))}
</div>
);
}
3. Адаптивные изображения (Responsive Images)
Показываем разные размеры для разных экранов:
import Image from 'next/image';
function ResponsiveImage({ src, alt }) {
return (
<Image
src={src}
alt={alt}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 75vw, 50vw"
responsive
quality={75}
/>
);
}
4. Сжатие изображений
Использую TinyPNG или ImageOptim для сжатия перед загрузкой на сервер:
// Клиентское сжатие перед отправкой
async function compressImage(file: File): Promise<Blob> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (event) => {
const img = new Image();
img.src = event.target?.result as string;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
canvas.toBlob(resolve, 'image/jpeg', 0.75);
};
};
});
}
5. Форматы изображений
Оптимальная иерархия форматов:
- WebP (лучше всего для современных браузеров)
- JPEG (универсальный)
- PNG (для прозрачности)
- AVIF (новый стандарт)
<picture>
<source srcSet="image.avif" type="image/avif" />
<source srcSet="image.webp" type="image/webp" />
<source srcSet="image.jpg" type="image/jpeg" />
<img src="image.jpg" alt="description" />
</picture>
6. Виртуализация списков
Для списков с сотнями изображений использую react-window:
import { FixedSizeList as List } from 'react-window';
function ImageList({ images }) {
const Row = ({ index, style }) => (
<div style={style}>
<Image
src={images[index].url}
alt={images[index].alt}
width={200}
height={200}
/>
</div>
);
return (
<List
height={600}
itemCount={images.length}
itemSize={220}
width="100%"
>
{Row}
</List>
);
}
7. Кеширование
Исползую Service Worker для кеширования изображений:
// service-worker.js
self.addEventListener('fetch', (event) => {
if (event.request.url.includes('/images/')) {
event.respondWith(
caches.open('images-v1').then((cache) => {
return cache.match(event.request).then((response) => {
return response || fetch(event.request).then((res) => {
cache.put(event.request, res.clone());
return res;
});
});
})
);
}
});
8. CDN для изображений
Использую Cloudinary или imgix для динамической трансформации:
const cloudinaryUrl = `https://res.cloudinary.com/${CLOUD_NAME}/image/upload/w_800,q_auto,f_webp/v${version}/${publicId}`;
<Image src={cloudinaryUrl} alt="optimized" width={800} height={600} />
9. Мониторинг производительности
function measureImagePerformance() {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name.includes('.jpg') || entry.name.includes('.png')) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
}
});
observer.observe({ entryTypes: ['resource'] });
}
Итоговая стратегия
- Next.js Image для автооптимизации
- Lazy loading для изображений ниже fold
- Адаптивные размеры через srcset
- Сжатие и WebP формат
- Виртуализация для больших списков
- Service Worker кеширование
- CDN для трансформации
- Регулярный мониторинг Core Web Vitals (LCP, FID, CLS)