← Назад к вопросам
Почему в 2024 году socket.io считается не лучшим выбором для WebSocket?
1.8 Middle🔥 121 комментариев
#API и сетевые протоколы#Фреймворки и библиотеки
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое libuv и какую роль она играет в Node.js?
libuv — это кроссплатформенная C библиотека, которая обеспечивает асинхронный I/O и Event Loop в Node.js. Это сердце Node.js.
Архитектура Node.js
┌─────────────────────────────────────┐
│ JavaScript (V8 engine) │ ← Ваш код
└────────────────┬────────────────────┘
│
┌───────▼────────┐
│ Node.js APIs │ (fs, http, crypto, etc)
└────────┬───────┘
│
┌────────▼────────────────┐
│ libuv (Event Loop) │ ← Асинхронный I/O
├──────────────────────────┤
│ - File System │
│ - Network I/O │
│ - Timers │
│ - Thread Pool │
└──────────────────────────┘
Основные компоненты libuv
1. Event Loop — ядро асинхронности
┌─────────────────────────────────────────────┐
│ Event Loop │
│ │
│ ┌────────────────────────────────────┐ │
│ │ 1. Timers (setTimeout, setInterval) │ │
│ │ 2. I/O callbacks (file ops) │ │
│ │ 3. Check (setImmediate) │ │
│ │ 4. Close callbacks │ │
│ └────────────────────────────────────┘ │
│ │
│ + Microtask Queue (Promise, nextTick) │
└─────────────────────────────────────────────┘
2. Thread Pool — для blocking операций
// fs.readFile использует thread pool
fs.readFile('huge-file.txt', (err, data) => {
// Чтение файла произошло в отдельном потоке
console.log(data);
});
// Это НЕ блокирует main thread
По умолчанию 4 потока, настраивается через:
UV_THREADPOOL_SIZE=8 node app.js
3. I/O Polling — ожидание I/O событий
libuv проверяет, готовы ли файловые дескрипторы:
- Сокеты готовы читать?
- Файлы готовы писать?
- Таймеры истекли?
Как libuv управляет асинхронностью
const fs = require('fs');
const http = require('http');
// 1. setTimeout
setTimeout(() => {
console.log('Timer callback');
}, 1000);
// 2. File I/O (использует thread pool)
fs.readFile('file.txt', (err, data) => {
console.log('File read');
});
// 3. HTTP запрос
http.get('https://api.example.com', (res) => {
console.log('HTTP response');
});
// libuv управляет всем этим:
// - Помещает setTimeout в очередь таймеров
// - Запускает readFile в thread pool
// - Регистрирует HTTP соединение
// - Event Loop проверяет, что готово
// - Вызывает колбэки
Event Loop в действии
const start = Date.now();
console.log('1');
setTimeout(() => {
console.log('2 - setTimeout (1ms)');
console.log(`Time elapsed: ${Date.now() - start}ms`);
}, 1);
Promise.resolve().then(() => {
console.log('3 - Promise');
});
fs.readFile(__filename, () => {
console.log('4 - fs.readFile');
});
console.log('5');
// Output:
// 1
// 5
// 3 - Promise
// 2 - setTimeout (1ms)
// 4 - fs.readFile
// Порядок выполнения:
// 1. Синхронный код (1, 5)
// 2. Microtask Queue (Promise = 3)
// 3. Timers phase (setTimeout = 2)
// 4. Poll phase (I/O = 4)
libuv обрабатывает разные ОС
Пороносимость благодаря libuv:
Node.js код
│
┌────▼────┐
│ libuv │
└────┬────┘
│ │ │
┌───▼─┬┴───┴─┬──┐
│ │ │
Linux macOS Windows
(epoll) (kqueue) (IOCP)
libuv скрывает разницу между операционными системами.
Практический пример: CPU-bound vs I/O-bound
// ✗ CPU-bound: блокирует Event Loop
function heavyComputation() {
let sum = 0;
for (let i = 0; i < 10**9; i++) {
sum += i;
}
return sum;
}
// Это затвердит весь сервер!
const result = heavyComputation();
// ✓ I/O-bound: использует libuv thread pool
fs.readFile('huge-file.txt', (err, data) => {
console.log(`Read ${data.length} bytes`);
// Event Loop свободен, может обрабатывать другие запросы!
});
libuv в боевых ситуациях
Проблема 1: Истощение thread pool
// ✗ ПЛОХО: Много CPU-bound операций в одно время
for (let i = 0; i < 1000; i++) {
crypto.pbkdf2(password, salt, 100000, 64, 'sha512', (err, derived) => {
// thread pool перегружен!
});
}
// ✓ ХОРОШО: Ограничить параллельность
const pLimit = require('p-limit');
const limit = pLimit(4);
const promises = passwords.map(pwd =>
limit(() => hashPassword(pwd))
);
await Promise.all(promises);
Проблема 2: Забытые операции
// ✗ ПЛОХО: операция в thread pool, но мы не ждём
fs.readFile('file.txt', () => {});
process.exit(0); // Выход до завершения чтения
// ✓ ХОРОШО: Graceful shutdown
process.on('SIGTERM', async () => {
console.log('Closing...');
server.close();
await db.close();
process.exit(0);
});
Мониторинг libuv
const { performance, PerformanceObserver } = require('perf_hooks');
// Смотрим, как долго выполняются операции
const obs = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
}
});
obs.observe({ entryTypes: ['measure'] });
performance.mark('fs-start');
fs.readFile('file.txt', () => {
performance.mark('fs-end');
performance.measure('fs', 'fs-start', 'fs-end');
});
Роль libuv в Node.js
- Event Loop — асинхронное управление
- Thread Pool — CPU-интенсивные операции
- I/O абстракция — файлы, сеть, pipes
- Кроссплатформенность — Windows, macOS, Linux
- Производительность — optimized для I/O операций
Вывод
libuv — это магический слой, который позволяет Node.js быть асинхронным и невероятно быстрым для I/O операций. Без него Node.js был бы простым синхронным интерпретатором JavaScript.