open atlas
↑ К треку
Node.js с нуля до senior NODE · 00 · 01

Что такое Node.js на самом деле

Node.js — это JavaScript вне браузера: V8 исполняет код, libuv даёт однопоточный event loop с неблокирующим I/O, а встроенная библиотека открывает файлы, сеть и процесс. Силён в I/O, слаб в тяжёлых вычислениях.

NODE Junior ◷ 14 min
Уровень
ОсновыJuniorMiddleSenior
Уже знаешь этот юнит? Пройди быструю проверку за минуту →

Ты выучил JavaScript, чтобы кнопка на странице меняла цвет. Потом тебе дают server.js и говорят: «запусти через node». Ни браузера, ни <button>, ни document — а оно при этом обслуживает десять тысяч API-запросов в один поток и не плавится. Тот же язык, которым ты переключал CSS-класс, теперь читает файлы с диска и общается с базой данных. Как? Node.js — это не новый язык. Это runtime, который берёт уже знакомый тебе JavaScript и запускает его там, куда браузер его не пускал: на сервере.

Runtime, а не язык: V8 + libuv + стандартная библиотека

Прежде чем написать первую строку серверного кода, стоит разобраться, что такое Node.js на самом деле — потому что модель, которую ты выстроишь здесь, объяснит каждую странность позже: почему нет window, почему один медленный эндпоинт может заморозить весь API.

Когда говорят «Node.js», имеют в виду три вещи, свинченные в одну программу.

Первая — это V8, тот же движок, что Chrome использует для исполнения JavaScript. V8 берёт твой .js-исходник, компилирует его в машинный код и быстро запускает. Но сам по себе V8 только понимает JavaScript; он понятия не имеет, как открыть файл или принять сетевое соединение. В спецификации языка нет ни fs, ни http, ни сокетов.

Вторая часть закрывает эту дыру: libuv — C-библиотека, дающая Node event loop (цикл событий — механизм, который бесконечно вынимает завершённые задачи из очереди и запускает колбэки) плюс асинхронный I/O (ввод-вывод — диск, сеть, таймеры). Именно libuv позволяет одному потоку ждать тысячи соединений сразу, а не блокироваться на каждом. Ещё она держит в фоне небольшой пул потоков для тех немногих операций, что ОС не умеет делать асинхронно (часть работы с файловой системой и криптографией).

Третья — это стандартная библиотека Node: встроенные модули, открывающие всё это для JavaScript: fs для файлов, http/net для серверов и сокетов, path, process для самой работающей программы, crypto, stream и другие. Именно её ты на самом деле require или import.

// Никакого браузера — это работа стандартной библиотеки.
import { readFile } from "node:fs/promises";
import http from "node:http";

const html = await readFile("./index.html", "utf8"); // libuv читает диск
http.createServer((req, res) => res.end(html))       // V8 исполняет твой колбэк
    .listen(3000);
console.log(`pid ${process.pid} слушает :3000`);      // process = эта программа

Зачем вообще нужна такая связка? До Node JavaScript был заперт в браузере, а серверы писали на PHP, Python, Ruby или Java. Node позволил командам писать на одном языке по всему стеку — и фронтенд, и бэкенд — и пользоваться огромной экосистемой пакетов npm (Node Package Manager — крупнейший реестр ПО в мире). Именно это решение объясняет большую часть того, почему Node захватил серверный тулинг.

Один поток, event loop и неблокирующий I/O

Вот идея, из-за которой Node кажется странным после других бэкендов: твой JavaScript исполняется в одном потоке. Никакого «поток на запрос». Как же один поток обслуживает тысячи клиентов?

Фокус в неблокирующем I/O. Когда твой код просит прочитать файл или сделать запрос к базе, Node не садится и не ждёт ответа. Он передаёт запрос в libuv (которая использует ОС или пул потоков), регистрирует колбэк и тут же переходит к другой работе. Когда данные готовы, libuv кладёт колбэк в очередь, и event loop — цикл, работающий бесконечно и вынимающий завершённую работу из очередей, чтобы исполнить колбэки, — его запускает. Один поток почти никогда не простаивает и почти никогда не заблокирован, поэтому он чередует тысячи операций «в полёте».

Есть и обратная сторона. Если дать этому единственному потоку CPU-bound работу — плотный цикл, хэширующий миллион паролей, ресайз огромной картинки, синхронный разбор гигантского JSON, — то некому принимать запросы, пока он молотит. Event loop заблокирован. Все остальные клиенты ждут. I/O разгружается; вычисления — нет.

Где Node силён, а где нет

Эта архитектура не лучше и не хуже бэкендов с «потоком на запрос» — она заточена под определённый род работы. Понимая эту заточку, ты знаешь, когда тянуться за Node.

АспектJavaScript в браузереJavaScript в Node.js
Где исполняетсяВнутри веб-страницы, во вкладке браузера пользователяКак отдельный процесс на сервере (или твоей машине)
ДвижокV8 (Chrome) / SpiderMonkey / JSCV8 + libuv (event loop, async I/O)
Платформенные APIDOM, fetch, localStorage, Web APIfs, net/http, crypto, child_process
Глобальный объектwindow / documentglobal / process (env, argv, pid)
Нет доступа кЛокальной файловой системе, сырым сокетамDOM, странице (страницы попросту нет)

Node отлично справляется с I/O-bound работой, потому что именно под неё созданы неблокирующий I/O и event loop: HTTP-API и микросервисы, которые в основном ждут базы и другие сервисы, real-time-системы (чаты, живые дашборды) поверх WebSocket и инструменты разработчика (бандлеры, линтеры, CLI), где доминирует чтение и запись файлов. И он слаб в тяжёлых CPU-bound вычислениях — перекодировании видео, больших численных симуляциях, объёмной синхронной криптографии — потому что такая работа блокирует единственный поток. Запасные выходы реальны, но осознанны: worker_threads, чтобы вынести вычисления с главного потока, или просто язык, лучше подходящий для перемалывания чисел.

Экосистема — вторая половина картины. npm — это реестр пакетов и установщик Node, крупнейший реестр ПО в мире. Поверх него лежат фреймворки, с которыми ты встретишься дальше: Express и Fastify для HTTP-серверов, NestJS для структурированных, «с мнением» бэкендов. Относись к этим названиям как к карте, а не как к домашке на сегодня.

Почему это работает

«Однопоточность» — формулировка слегка неточная, и полезно понимать почему. Твой JavaScript исполняется в одном потоке, но Node как процесс — нет. libuv держит фоновый пул потоков (по умолчанию 4) для операций с файловой системой и криптографией, которые ОС не умеет делать асинхронно, а ты можешь поднять настоящие worker_threads для параллельных вычислений. Модель «один поток» описывает исполнение твоего кода и event loop — а не весь runtime. Практический вывод не меняется: не блокируй этот единственный JS-поток синхронными вычислениями.

Викторина

Коллега говорит: «Node.js — это новый язык программирования для сервера». В чём точная поправка?

Викторина

Один поток Node обслуживает тысячи HTTP-запросов, каждый из которых ходит в базу. Затем ты добавляешь эндпоинт, синхронно ресайзящий огромные картинки. Что произойдёт?

Выбери лучший вариант

Ты решаешь, подходит ли Node.js под нагрузку. Что из этого — конёк Node, а что воюет с его моделью?

Вспомните перед уходом
  1. 01
    Назови три части, из которых состоит Node.js, и что делает каждая.
  2. 02
    Node исполняет твой JS в одном потоке. Объясни, как он всё же обслуживает тысячи клиентов, и какой единственный род работы это ломает.
Итог

Node.js — это не новый язык, а runtime, который запускает уже знакомый тебе JavaScript вне браузера. Он свинчивает три вещи: V8, исполняющий твой JS; libuv, дающую event loop, асинхронный I/O и небольшой фоновый пул потоков; и стандартную библиотеку (fs, http, net, path, process, crypto), открывающую файловую систему, сеть и сам процесс твоему коду. Он появился потому, что позволил писать на одном языке по всему стеку и пользоваться огромной экосистемой npm. Его определяющая модель — единственный JavaScript-поток, управляемый event loop с неблокирующим I/O: медленное ожидание запроса разгружается в libuv, чтобы один поток оставался свободным и обслуживал тысячи других, запуская каждый колбэк, когда его данные готовы. Это делает Node отличным в I/O-bound API, real-time-системах и тулинге разработчика — и слабым в тяжёлых вычислениях, которые блокируют поток и требуют worker_threads или другого языка. В отличие от браузерного JS здесь нет DOM или window; вместо них — global, process и стандартная библиотека. Теперь, когда встретишь API, который необъяснимо тормозит под нагрузкой — даже если он «только читает из базы», — у тебя будет словарь, чтобы задать правильный вопрос: что-то блокирует event loop?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.