Оптимизация JavaScript: производительность, размер bundle и загрузка
Оптимизация JavaScript напрямую влияет на скорость загрузки страницы и производительность взаимодействия (INP). Это руководство охватывает уменьшение bundle, code splitting, lazy loading и техники производительности.
Обновлено:Почему производительность JavaScript важна
JavaScript — это самый потребляющий CPU ресурс в браузере. Большие JS-файлы увеличивают время парсинга и компиляции и негативно влияют на метрику INP.
Обычно JavaScript составляет 40-60% веса страницы. Неиспользуемый JavaScript вызывает ненужное потребление CPU и памяти.
Оптимизация JavaScript улучшает метрики Core Web Vitals (особенно INP и LCP). Оптимизированный JS обеспечивает более быстрый и отзывчивый пользовательский опыт.
Оптимизация размера bundle
Tree shaking: удалите неиспользуемые экспорты. Используйте ES modules (import/export). CommonJS (require) не поддерживает tree shaking.
Анализ bundle: визуализируйте содержимое bundle с помощью webpack-bundle-analyzer или rollup-plugin-visualizer. Определите, какие библиотеки занимают больше всего места.
Альтернативные библиотеки: day.js вместо moment.js (2KB vs 300KB), lodash-es или нативные методы вместо lodash. Замените большие библиотеки более лёгкими альтернативами.
Аудит зависимостей: обнаружьте неиспользуемые зависимости с помощью npm ls или depcheck. Удалите ненужные зависимости из package.json.
Code Splitting
Route-based splitting: создавайте отдельный bundle для каждой страницы. Lazy load компоненты страниц с помощью React.lazy() и Suspense.
Component-based splitting: разделите тяжёлые компоненты (modal, chart, editor) на отдельные chunks. Загружайте по требованию с помощью dynamic import().
Vendor splitting: разделите зависимости node_modules на отдельный vendor chunk. Vendor chunk не меняется и остаётся в кэше браузера.
Webpack: автоматический code splitting с optimization.splitChunks. Vite: автоматический code splitting Rollup. Next.js: автоматический route-based splitting.
Lazy Loading
Dynamic import(): модуль загружается по требованию с помощью const module = await import('./heavy-module.js');.
Intersection Observer: загружайте компонент, когда он виден. Lazy load компоненты below-the-fold с помощью React.lazy + Intersection Observer.
Prefetch и preload: prefetch некритичные модули в фоне. Браузер загружает в простое с помощью <link rel="prefetch" href="chunk.js">.
React Suspense: показывайте состояние загрузки для lazy loaded компонентов с помощью <Suspense fallback={<Loading />}><LazyComponent /></Suspense>.
Техники производительности
Debounce и throttle: используйте debounce/throttle на событиях scroll, resize и input. Реализуйте с помощью Lodash debounce или нативного setTimeout.
Web Workers: отделяйте тяжёлые вычисления от главного потока. Выполняйте CPU-интенсивную работу в фоне с помощью new Worker('worker.js').
requestAnimationFrame: синхронизируйте анимации и обновления DOM с помощью requestAnimationFrame. Цельтесь на 60fps.
Virtual scrolling: рендерите только видимые элементы в больших списках (1000+ элементов). Используйте react-window или vue-virtual-scroller.
Memoization: предотвращайте ненужные вычисления и повторные рендеры с помощью useMemo, useCallback и React.memo.
Измерение и мониторинг
Lighthouse Performance audit: проверяйте метрики времени выполнения JavaScript, неиспользуемый JavaScript и размер bundle.
Chrome DevTools Performance tab: анализируйте время выполнения JavaScript, скриптинга и рендеринга. Обнаруживайте long tasks и блокировку главного потока.
Web Vitals: отслеживайте метрики INP, LCP и CLS. Собирайте данные реальных пользователей с помощью библиотеки web-vitals.
Real User Monitoring (RUM): отслеживайте данные производительности реальных пользователей с помощью Sentry, Datadog или New Relic.