Пост

Оптимизация производительности веб-приложений: от загрузки до отображения

Подробное руководство по оптимизации производительности веб-приложений. Изучите методы улучшения скорости загрузки, отзывчивости интерфейса и общей эффективности приложения.

Оптимизация производительности веб-приложений: от загрузки до отображения

Введение

Производительность веб-приложений напрямую влияет на пользовательский опыт и SEO. В этой статье мы рассмотрим комплексный подход к оптимизации.

Почему важна производительность?

  • Пользовательский опыт: Быстрая загрузка и отзывчивость
  • SEO: Высокие метрики Core Web Vitals
  • Конверсия: Увеличение конверсии при хорошей производительности
  • Затраты: Оптимизация использования ресурсов

Оптимизация фронтенда

1. Оптимизация загрузки

Минификация и сжатие

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// webpack.config.js
module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin(),
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip'
    })
  ]
};

Код-сплиттинг

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// React Router с ленивой загрузкой
const Dashboard = React.lazy(() => import('./Dashboard'));
const Profile = React.lazy(() => import('./Profile'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </Suspense>
  );
}

2. Оптимизация изображений

Ленивая загрузка

1
2
3
4
5
6
<img 
  src="placeholder.jpg"
  data-src="actual-image.jpg"
  loading="lazy"
  alt="Description"
>

Оптимизация форматов

1
2
3
4
5
6
// Использование современных форматов
<picture>
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="Description">
</picture>

3. Кэширование

Service Worker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// service-worker.js
const CACHE_NAME = 'v1';
const urlsToCache = [
  '/',
  '/styles.css',
  '/script.js'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

HTTP кэширование

1
2
3
4
5
# nginx.conf
location /static/ {
    expires 1y;
    add_header Cache-Control "public, no-transform";
}

Оптимизация бэкенда

1. Оптимизация базы данных

Индексация

1
2
3
4
5
-- Создание индекса
CREATE INDEX idx_users_email ON users(email);

-- Составной индекс
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);

Оптимизация запросов

1
2
3
4
5
// Использование проекций
const user = await User.findById(id).select('name email');

// Использование lean()
const users = await User.find().lean();

2. Кэширование на сервере

Redis кэширование

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const redis = require('redis');
const client = redis.createClient();

async function getUser(id) {
  // Проверка кэша
  const cached = await client.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  // Получение из БД
  const user = await User.findById(id);
  
  // Сохранение в кэш
  await client.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
  
  return user;
}

Кэширование в памяти

1
2
3
4
5
6
7
8
9
10
11
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 });

function getCachedData(key) {
  let data = cache.get(key);
  if (!data) {
    data = fetchData();
    cache.set(key, data);
  }
  return data;
}

Мониторинг производительности

1. Метрики Core Web Vitals

Измерение LCP

1
2
3
4
5
6
7
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP:', entry.startTime);
    // Отправка метрики
    sendToAnalytics('LCP', entry.startTime);
  }
}).observe({ entryTypes: ['largest-contentful-paint'] });

Измерение FID

1
2
3
4
5
6
7
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('FID:', entry.processingStart - entry.startTime);
    // Отправка метрики
    sendToAnalytics('FID', entry.processingStart - entry.startTime);
  }
}).observe({ entryTypes: ['first-input'] });

2. Мониторинг сервера

Метрики Node.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const promClient = require('prom-client');

// Создание метрик
const httpRequestDuration = new promClient.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status']
});

// Использование в middleware
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const duration = Date.now() - start;
    httpRequestDuration
      .labels(req.method, req.route.path, res.statusCode.toString())
      .observe(duration / 1000);
  });
  next();
});

Оптимизация сети

1. HTTP/2

Настройка Nginx

1
2
3
4
# nginx.conf
http2 on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

2. CDN

Настройка CDN

1
2
3
4
5
6
// Использование CDN для статических ресурсов
const CDN_URL = 'https://cdn.example.com';

// В HTML
<link rel="stylesheet" href="${CDN_URL}/styles.css">
<script src="${CDN_URL}/script.js"></script>

Оптимизация сборки

1. Tree Shaking

Настройка webpack

1
2
3
4
5
6
7
// webpack.config.js
module.exports = {
  optimization: {
    usedExports: true,
    sideEffects: true
  }
};

2. Оптимизация бандлов

Анализ бандлов

1
2
3
4
5
6
7
8
9
10
11
# Установка анализатора
npm install --save-dev webpack-bundle-analyzer

# Добавление в webpack
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

Оптимизация изображений

1. Оптимизация на этапе сборки

Настройка image-webpack-loader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        use: [
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65
              },
              optipng: {
                enabled: false
              },
              pngquant: {
                quality: [0.65, 0.90],
                speed: 4
              }
            }
          }
        ]
      }
    ]
  }
};

2. Оптимизация на лету

Использование Sharp

1
2
3
4
5
6
7
8
9
10
11
const sharp = require('sharp');

async function optimizeImage(input, output) {
  await sharp(input)
    .resize(800, 600, {
      fit: 'inside',
      withoutEnlargement: true
    })
    .webp({ quality: 80 })
    .toFile(output);
}

Заключение

Оптимизация производительности - это комплексный процесс, который требует внимания к различным аспектам разработки. Используйте инструменты мониторинга, следите за метриками и постоянно улучшайте производительность вашего приложения.

Полезные ресурсы

Авторский пост защищен лицензией CC BY 4.0 .

© Oleg Dobrynin. Некоторые права защищены.