Node.js
Node.js — это среда выполнения, встраивающая движок V8 и библиотеку libuv, чтобы JavaScript работал на сервере: файлы, сеть, процессы. Модель здесь та же, что и в браузере, — однопоточный событийный цикл, — но на сервере эта однопоточность превращается из фоновой детали в главное ограничение, вокруг которого строится вся архитектура.
Node силён в I/O-нагрузке: пока он ждёт сеть или диск, событийный цикл обслуживает тысячи других соединений, не блокируясь. И он слаб в CPU-нагрузке: одна длинная синхронная функция занимает единственный поток и тормозит все прочие запросы, пока не завершится. Отсюда растут четыре продвинутые темы: как устроены фазы цикла, как выйти за один поток через worker_threads и child_process, как потоки держат память ровной через backpressure и как корректно завершить процесс, не оборвав живые запросы. Каждый механизм разобран в слоях ниже.
Карта темы
- Среда выполнения Node — V8 плюс
libuv, однопоточный event loop и почему Node хорош для I/O и плох для CPU. - Фазы event loop — упорядоченные фазы
libuv, микрозадачи и местоsetImmediateпротивprocess.nextTick. - Многоядерная конкурентность —
worker_threadsпротивchild_processи модуль cluster для раскладки по ядрам. - Потоки и backpressure — четыре типа потоков, обработка данных по частям и backpressure через
pipe. - Жизненный цикл и graceful shutdown — корректное завершение по
SIGTERMс дренированием запросов и таймаутом.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
| Запускать CPU-тяжёлую синхронную работу в главном потоке | Блокируется event loop, встают все ожидающие запросы |
| Считать Node многопоточным для прикладного кода | Ожидание параллелизма там, где его нет без worker'ов или cluster |
Считать setImmediate идентичным setTimeout(0) | Разные фазы; на верхнем уровне порядок не гарантирован |
Думать, что микрозадачи промисов идут раньше process.nextTick | process.nextTick опустошается первым — неверная модель порядка |
| Читать большой файл целиком в память | Расход памяти растёт с размером файла вместо ровного через поток |
| Игнорировать backpressure | Быстрый источник переполняет медленный приёмник |
Выходить по SIGTERM сразу | Обрываются живые запросы, текут соединения при передеплоях |
Значение для собеседований
Node.js — ядро backend-секции, и здесь проверяют не знание API, а модель выполнения. Кандидат, который объясняет «единственный поток обслуживает I/O не блокируясь, но одна CPU-задача его останавливает», сразу показывает, что понимает суть, а не заучил «Node асинхронный».
Что обычно проверяют:
- Почему Node хорош для I/O и плох для CPU и как не заблокировать event loop.
- Фазы event loop и порядок
setImmediate/setTimeout(0)/process.nextTick. - Разницу
worker_threadsиchild_processи когда какой брать. - Что решают потоки и backpressure; что такое graceful shutdown и зачем таймаут.
Типичный неверный ответ: «Node многопоточный, тяжёлые вычисления идут параллельно сами собой». На самом деле прикладной JavaScript исполняется в одном потоке; параллелизм даёт только явный worker_threads, child_process или cluster, а синхронная CPU-работа в главном потоке замораживает весь сервер.