Як оптимізувати продуктивність додатку Express.js?
Оптимізація продуктивності Express.js
Оптимізація Express.js передбачає зменшення часу відповіді, обробку більшої кількості одночасних запитів та ефективне використання ресурсів.
1. Увімкніть стиснення
js
const compression = require('compression');
app.use(compression({
level: 6,
threshold: 1024,
filter: (req, res) => {
if (req.headers['x-no-compression']) return false;
return compression.filter(req, res);
}
}));Зменшує розмір відповіді на 60-80% для JSON та тексту.
2. Використовуйте зворотний проксі (Nginx)
nginx
upstream nodejs {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
keepalive 64;
}
server {
listen 80;
# Обслуговування статичних файлів безпосередньо
location /static/ {
root /var/www/public;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://nodejs;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}3. Встановіть NODE_ENV=production
bash
NODE_ENV=production node server.jsExpress кешує шаблони переглядів та генерує менш об'ємні повідомлення про помилки в режимі виробництва. Багато пакетів також оптимізують свою поведінку.
4. Оптимізація запитів до бази даних
js
// ❌ Проблема N+1
const users = await User.findAll();
for (const user of users) {
user.posts = await Post.findAll({ where: { userId: user.id } });
}
// ✅ Жадібне завантаження
const users = await User.findAll({
include: [{ model: Post }]
});
// ✅ Використовуйте індекси
// CREATE INDEX idx_posts_user_id ON posts(user_id);5. Найкращі практики Async/Await
js
// ❌ Послідовно — повільно
const users = await getUsers();
const products = await getProducts();
const orders = await getOrders();
// ✅ Паралельно — швидко
const [users, products, orders] = await Promise.all([
getUsers(),
getProducts(),
getOrders()
]);6. Використовуйте стрімінг для великих відповідей
js
app.get('/api/export', async (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.write('[');
const cursor = db.collection('records').find().stream();
let first = true;
cursor.on('data', (doc) => {
if (!first) res.write(',');
res.write(JSON.stringify(doc));
first = false;
});
cursor.on('end', () => {
res.write(']');
res.end();
});
});7. Пулінг з'єднань
js
const pool = new Pool({
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000
});8. Використовуйте кластерний режим
js
const cluster = require('cluster');
const os = require('os');
if (cluster.isPrimary) {
const cpuCount = os.cpus().length;
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
cluster.on('exit', (worker) => {
console.log(`Робітник ${worker.process.pid} помер, перезапускаємо...`);
cluster.fork();
});
} else {
const app = require('./app');
app.listen(3000);
}Контрольний список продуктивності
| Оптимізація | Вплив | Складність |
|---|---|---|
compression middleware | Високий | Легко |
NODE_ENV=production | Середній | Тривіально |
| Зворотний проксі (Nginx) | Високий | Середній |
| Індекси бази даних | Дуже високий | Середній |
| Пулінг з'єднань | Високий | Легко |
| Кешування (Redis) | Дуже високий | Середній |
| Кластерний режим / PM2 | Високий | Легко |
Promise.all для паралельних запитів | Середній | Легко |
| Стрімінг великих даних | Середній | Середній |
| Уникати синхронних операцій | Високий | Легко |
| Використовуйте CDN для статичних файлів | Високий | Легко |
Основний висновок: Більшість проблем продуктивності Express виникають через запити до бази даних, а не через сам Express. Спочатку оптимізуйте запити (індекси, жадібне завантаження, кешування), а потім інфраструктуру (Nginx, кластер, стиснення).
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.