← Назад к вопросам

Как работает Node.js?

1.8 Middle🔥 241 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Архитектура Node.js

Node.js — это асинхронная, событийно-ориентированная платформа для выполнения JavaScript на сервере. Её работа основана на трёх ключевых компонентах:

1. Event Loop (Цикл событий)

Event Loop — сердце Node.js. Это бесконечный цикл, который проверяет наличие задач и выполняет их.

// Упрощённая модель Event Loop
while (eventLoop.waitForTask()) {
  const macrotask = eventLoop.nextMacrotask();
  if (macrotask) macrotask();
  
  const microtasks = eventLoop.nextMicrotasks();
  microtasks.forEach(task => task());
}

Event Loop проходит несколько фаз:

  • Timers — выполнение callbacks из setTimeout/setInterval
  • I/O callbacks — асинхронные операции файловой системы, сети
  • Check — setImmediate callbacks
  • Close — закрытие соединений

2. libuv (Асинхронная I/O библиотека)

libuv предоставляет асинхронную обработку I/O операций через thread pool:

// Пример асинхронной операции
import fs from 'fs';

fs.readFile('file.txt', 'utf-8', (err, data) => {
  if (err) console.error(err);
  else console.log(data);
});

console.log('Это выполнится раньше!');

При чтении файла:

  1. Задача добавляется в очередь libuv
  2. Рабочий поток из pool'а выполняет I/O
  3. После завершения callback попадает в очередь Event Loop
  4. Event Loop выполняет callback

3. V8 JavaScript Engine

V8 компилирует и выполняет JavaScript код. Он использует:

  • JIT компиляцию для оптимизации горячего кода
  • Garbage Collection для управления памятью
// V8 оптимизирует этот код
function add(a, b) {
  return a + b;
}

// После нескольких вызовов V8 создаст machine code для этой функции
for (let i = 0; i < 1000000; i++) {
  add(i, i + 1);
}

Порядок выполнения кода

Важно понимать микротаски vs макротаски:

console.log('1'); // Синхронный код

setTimeout(() => console.log('2'), 0); // Макротаска (Timers)

Promise.resolve()
  .then(() => console.log('3')); // Микротаска (Microtask Queue)

setImmediate(() => console.log('4')); // Макротаска (Check фаза)

console.log('5'); // Синхронный код

// Результат: 1, 5, 3, 2, 4

Порядок выполнения:

  1. Всё синхронный код (1, 5)
  2. Все микротаски: Promises, queueMicrotask (3)
  3. Первый макротаск: setTimeout (2)
  4. Микротаски после (если есть)
  5. Следующий макротаск: setImmediate (4)

Non-blocking I/O

Главное преимущество Node.js — неблокирующие операции:

// ❌ Блокирующий код (избегать!)
const data = fs.readFileSync('file.txt', 'utf-8');
console.log(data); // Ждёт, пока файл прочитается

// ✅ Неблокирующий код
fs.readFile('file.txt', 'utf-8', (err, data) => {
  console.log(data);
});
console.log('Продолжаем дальше'); // Выполнится сразу

Это позволяет обрабатывать тысячи параллельных операций на одном потоке.

Управление памятью

Node.js использует V8 Garbage Collection:

// Утечки памяти возникают при:
const cache = {}; // Растёт бесконечно
function addToCache(key, value) {
  cache[key] = value; // Никогда не удаляется
}

// ✅ Правильно: используй LRU Cache или установи лимит
import LRU from 'lru-cache';
const cache = new LRU({ max: 100 });

Производительность

  • Node.js оптимален для I/O-heavy операций (API, базы данных)
  • Не подходит для CPU-intensive задач (обработка видео, расчёты)
  • Для CPU-heavy используй Worker Threads или native modules