Menu
Русский

Node.js runtime: как работает JavaScript вне браузера

Разбираемся, что такое Node.js runtime, чем он отличается от браузера и какие встроенные API — globals, модули, process, fs — делают серверный JavaScript возможным.

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

Node.js — это программа, которую вы ставите на свой компьютер, и она запускает JavaScript-файлы. Проще не скажешь, и это правда. Когда вы пишете в терминале node script.js, Node читает файл, передаёт его движку V8 от Google (тот самый JavaScript-движок из Chrome) и исполняет — плюс сверху навешана огромная библиотека API для всего того, что V8 сам по себе не умеет.

V8 умеет выполнять JavaScript. Но он понятия не имеет, как открыть файл, слушать TCP-сокет, запустить дочерний процесс или прочитать переменную окружения. Всё это даёт Node: написано на C++ и доступно из вашего JavaScript в виде встроенных модулей.

node --version
node script.js

Итак, Node — это не язык. И не фреймворк. Это runtime: движок V8 плюс стандартная библиотека, система модулей и event loop. Вот и всё, собственно.

Первый скрипт

Любой .js-файл — это уже готовая программа для Node. Никакого бойлерплейта, никакой функции main:

index.js
Output
Click Run to see the output here.

console.log в Node работает точно так же, как в браузере. Шаблонные строки, Date, массивы, промисы — все возможности самого языка достаются нам от V8 и ведут себя одинаково. В Node меняется не сам язык, а то, что доступно вокруг него.

Глобальные объекты, которых нет в браузере

В браузере есть window, document, localStorage, fetch. У Node свой набор глобальных объектов — заточенный под серверный рантайм:

index.js
Output
Click Run to see the output here.
  • process — это сам запущенный процесс Node. Через него вы получаете переменные окружения (process.env), аргументы командной строки (process.argv) и методы завершения работы (process.exit(1)).
  • __filename и __dirname возвращают абсолютный путь к текущему файлу и его папке соответственно. (В ES-модулях их нет — вместо них используется import.meta.url.)
  • global — это глобальный объект верхнего уровня, аналог window из браузера.

В Node нет ни document, ни window. Попытка обратиться к ним выбросит ReferenceError. Обычно это первый признак того, что библиотека писалась под браузер и в Node просто так не заведётся.

Аргументы командной строки и переменные окружения

Огромная часть задач, ради которых вообще берут Node, — CLI-утилиты, сборочные скрипты, серверы — так или иначе упирается в чтение аргументов и переменных окружения. И то и другое живёт на объекте process:

index.js
Output
Click Run to see the output here.

process.argv — это массив, где первые два элемента содержат путь к бинарнику Node и путь к запускаемому скрипту, так что реальные аргументы начинаются с индекса 2. process.env — обычный объект с переменными окружения; читать из него NODE_ENV, PORT или API-ключи — общепринятая практика.

Встроенные модули Node.js

В Node из коробки идёт стандартная библиотека, к которой обращаются через require (CommonJS) либо import (ESM). Имена модулей начинаются с префикса node: — так сразу видно, что это встроенные модули:

index.js
Output
Click Run to see the output here.

Чаще всего вам понадобятся:

  • node:fs — чтение и запись файлов. Для варианта с async/await берите node:fs/promises.
  • node:path — склейка, резолвинг и разбор путей к файлам так, чтобы код работал на любой ОС.
  • node:http / node:https — HTTP-серверы и отправка запросов.
  • node:url — разбор и сборка URL.
  • node:os — информация о машине, на которой запущен код.
  • node:crypto — хеширование, случайные байты, шифрование.

Ставить их отдельно не нужно — это встроенные модули Node js, они идут из коробки. Всё остальное тянется из npm.

Event loop в Node js, если коротко

Node выполняет ваш JavaScript в одном потоке, но при этом успевает заниматься кучей дел параллельно. Секрет — в event loop. Когда вы вызываете что-то асинхронное — чтение файла, HTTP-запрос, таймер — Node передаёт саму работу операционной системе (или своему пулу потоков) и спокойно идёт дальше по коду. Как только работа завершается, в очередь попадает колбэк, и цикл подхватывает его, едва текущий код досчитает своё.

index.js
Output
Click Run to see the output here.

Порядок вывода будет такой: 1, 4, 2 (микрозадача), 3 (после 0 мс). Сначала отрабатывает синхронный код. Затем микрозадачи (resolved-промисы). И только потом — таймеры. Именно поэтому тяжёлый CPU-bound цикл блокирует сервер целиком: для вашего кода поток всего один. Параллелизм в Node крутится вокруг I/O, а не вычислений.

Простой HTTP-сервер на Node.js

И вот ради чего всё это затевалось: рабочий веб-сервер умещается в несколько строк:

index.js
Output
Click Run to see the output here.

Без фреймворков и зависимостей. createServer принимает функцию, которая вызывается на каждый запрос, а listen запускает event loop для обработки входящих соединений. В реальных проектах поверх этого обычно лежит Express или Fastify, но под капотом — всё тот же встроенный модуль http.

Node.js против браузера

Стоит чётко разобраться, что работает и там и там, а что — только в одной среде:

Работает вездеТолько Node.jsТолько в браузере
Возможности языка (классы, промисы, async/await)fs, http, process, __dirnamewindow, document, DOM
console.logCommonJS require и особенности ESM в NodelocalStorage, sessionStorage
fetch (начиная с Node 18)Доступ к файловой системе и сетевым сокетамПользовательские события, отрисовка
setTimeout, setIntervalДочерние процессы, потоки (streams)History API, navigator

Современный Node подтянул к себе ряд браузерных API — fetch, URL, AbortController, structuredClone — так что разрыв стал меньше, чем раньше. Но DOM в Node не приедет, а файловая система в браузере не появится.

Node vs Deno vs Bun

Node — выбор по умолчанию, но давно не единственный JavaScript-рантайм. Есть альтернативы: Deno — от автора самого Node, и Bun — от более молодой команды, которая делает ставку на скорость. Оба запускают JavaScript (и TypeScript — прямо из коробки, без настройки), идут вместе со встроенными инструментами вроде тест-раннера и бандлера, и отличаются от Node подходом к модулям, правам доступа и установке пакетов.

Но если вы учите JavaScript, то вся документация, туториалы и вакансии пока крутятся вокруг Node. А ключевые концепции — event loop, модули, встроенные API — переносятся на другие рантаймы практически без изменений. Так что сначала Node, а остальное — когда конкретный проект этого потребует.

Как быстро запускать скрипты

Несколько способов действительно запустить код во время работы:

# Запуск файла
node script.js

# Запуск однострочника
node -e "console.log(2 ** 10)"

# Открыть REPL (интерактивную консоль)
node

# Отслеживать файл и перезапускать при сохранении (Node 18.11+)
node --watch script.js

REPL — удобная песочница, когда нужно быстро проверить, что возвращает какой-нибудь метод, и лень создавать файл. Флаг --watch пригодится в процессе разработки: сохранил — и Node сам перезапустил скрипт.

Дальше: ловим ошибки

Запустить код — это половина дела. Вторая — разобраться, что делать, когда всё пошло не так. Чтение файла падает, HTTP-запрос уходит в таймаут, JSON.parse кидает исключение. В следующей главе как раз поговорим про try/catch, типы ошибок и подходы к обработке того, что ломается, — а в Node-программе рано или поздно ломается всё.

Часто задаваемые вопросы

Что такое Node.js runtime?

Node.js — это среда, которая запускает JavaScript вне браузера. Внутри — движок V8 от Google (тот самый, что крутит JS в Chrome) плюс слой на C++, добавляющий то, чего у V8 самого по себе нет: работу с файловой системой, сетью, процессами, таймерами. Именно эта связка и позволяет писать на JavaScript серверы, CLI-утилиты и инструменты для сборки.

Чем Node отличается от браузера?

Язык один и тот же, но API вокруг него разные. В браузере есть window, document и DOM. В Node — process, fs, http, __dirname и загрузка модулей через CommonJS или ESM. DOM в Node нет, а файловой системы нет в браузере — язык общий, а платформы совершенно разные.

Node.js — это фреймворк или runtime?

Это runtime. Сам Node не навязывает никакой структуры приложения — он просто исполняет JavaScript и предоставляет API. А вот Express, Next.js или NestJS — это уже фреймворки поверх Node. Deno и Bun — альтернативные JS-рантаймы, которые конкурируют с Node, но решают ту же задачу.

Что такое event loop в Node?

Event loop — это механизм, благодаря которому Node успевает делать кучу дел одновременно, работая в одном потоке. Когда вы вызываете что-то асинхронное — чтение файла, HTTP-запрос, setTimeout — Node передаёт работу системе и продолжает выполнять код дальше. Как только работа завершилась, её колбэк попадает в очередь, а event loop его оттуда достаёт. Именно поэтому fs.readFile не блокирует всю остальную программу.

Учитесь программировать с Coddy

НАЧАТЬ