Node.js — это среда выполнения JavaScript вне браузера: она берёт тот же язык, на котором вы пишете интерфейсы, и позволяет запускать его на сервере, в терминале и на вашем компьютере. На Node.js работают API и бэкенды, чаты, консольные утилиты и почти весь современный фронтенд-инструментарий — от npm до Vite. Понимание того, из чего состоит Node и чем он отличается от браузера, избавит вас от множества ошибок в следующих темах.

Из чего состоит Node.js

Node.js — не язык и не фреймворк, а среда выполнения (runtime): программа, которая читает ваш .js-файл и выполняет его. Её создал Райан Даль в 2009 году, соединив быстрый JavaScript-движок из Chrome с библиотекой асинхронного ввода-вывода. Внутри Node четыре основных слоя:

КомпонентЯзыкЧто делает
V8C++Движок JavaScript из Chrome: разбирает код, компилирует его в машинный код (JIT), управляет памятью и сборкой мусора
libuvCEvent loop и асинхронный ввод-вывод: файлы, сеть, таймеры, пул потоков; одинаково работает в Linux, macOS и Windows
C++-привязки (bindings)C++«Мост» между JavaScript и системными библиотеками: когда вы вызываете fs.readFile, привязка передаёт запрос в libuv
Стандартная библиотекаJavaScriptВстроенные модули node:fs, node:http, node:path, node:crypto, node:os и другие

Кроме того, в Node встроены OpenSSL (шифрование и HTTPS), llhttp (разбор HTTP), undici (реализация fetch), ICU (поддержка языков и дат) и другие библиотеки. Версии всех компонентов хранятся в объекте process.versions — его удобно смотреть однострочником node -p, о котором подробнее в теме «REPL и запуск скриптов»:

bash
node -p "process.versions"
text
{
  node: '24.21.0',
  acorn: '8.18.0',
  ...
  openssl: '3.5.8',
  undici: '7.29.1',
  uv: '1.52.1',
  v8: '13.6.233.17-node.53',
  ...
}

Здесь видно, что Node 24.21 работает на V8 13.6 и libuv 1.52. Версия V8 определяет, какие новые возможности JavaScript доступны: если движок поддерживает синтаксис, его поддерживает и Node.

💡 Упрощённо: V8 отвечает за то, как выполнить JavaScript, а libuv — за то, как дождаться диска и сети, не останавливая программу. Как именно это работает, разберём в теме «Event loop в Node.js».

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

Для скрипта не нужны HTML и браузер — только файл и терминал. Создайте в любой папке файл hello.js:

js
console.log('Hello from Node.js!');
console.log(2 + 3);
console.log(`Node version: ${process.version}`);
console.log(`Platform: ${process.platform}, architecture: ${process.arch}`);

Запустите его командой node с именем файла (терминал должен находиться в той же папке):

bash
node hello.js
text
Hello from Node.js!
5
Node version: v24.21.0
Platform: linux, architecture: x64

console.log выводит текст не в консоль DevTools, а прямо в терминал. process.version — версия Node, process.platform — операционная система (linux, darwin для macOS, win32 для Windows), process.arch — архитектура процессора. У вас значения могут отличаться. Когда код в файле заканчивается и ждать больше нечего, Node сам завершает процесс.

Что умеет Node, но не умеет браузер

Браузер из соображений безопасности держит страницу в «песочнице»: она не может свободно читать файлы на диске или узнать имя пользователя. У Node таких ограничений нет — у скрипта те же права, что у вашего пользователя в системе. Сохраните этот пример в файл files.mjs (расширение .mjs говорит Node, что это ES-модуль с import; подробнее — в теме «ES-модули в Node.js»):

js
import { writeFile, readFile } from 'node:fs/promises';
import os from 'node:os';

await writeFile('note.txt', 'Written by Node.js');  // создаём файл на диске
const text = await readFile('note.txt', 'utf8');    // читаем его обратно
console.log(text);

console.log(`OS: ${os.type()}, CPU cores: ${os.availableParallelism()}`);
console.log(`Home folder: ${os.homedir()}`);
text
Written by Node.js
OS: Linux, CPU cores: 4
Home folder: /home/aysel

После запуска рядом со скриптом появится файл note.txt. Встроенные модули подключаются с префиксом node: — так сразу видно, что это часть Node, а не пакет из npm. Модуль node:fs/promises работает с файлами, node:os — с информацией о системе.

Node.js и браузер: общий язык, разное окружение

Язык один и тот же — стандарт ECMAScript: переменные, функции, классы, промисы, async/await работают одинаково. Различается окружение — набор глобальных объектов и API, которые даёт среда:

БраузерNode.js
Глобальный объектwindow (и globalThis)globalThis (старое имя — global)
Страница и DOMdocument, querySelector, события кликовнет
Диалогиalert, prompt, confirmнет
Файловая системанет (только через выбор файла пользователем)node:fs
Информация о процессенетprocess: версия, переменные окружения, аргументы
Двоичные данныеArrayBuffer, Blobто же + Buffer
Общие Web APIfetch, URL, setTimeout, console, structuredClone, AbortControllerте же самые

Проверим это на практике. Файл globals.js:

js
console.log(typeof window);          // → undefined
console.log(typeof document);        // → undefined
console.log(typeof globalThis);      // → object
console.log(globalThis === global);  // → true
console.log(typeof process, typeof Buffer);          // → object function
console.log(typeof fetch, typeof setTimeout);        // → function function

globalThis — стандартное имя глобального объекта, которое работает везде: в браузере, в Node, в воркерах. Используйте его, когда пишете код, который должен запускаться в обеих средах. Многие Web API (fetch, URL, TextEncoder, AbortController, crypto.randomUUID) в Node встроены и ведут себя так же, как в браузере, поэтому знания из фронтенда переносятся напрямую.

⚠️ Раз у скрипта полный доступ к файлам и сети, запускайте только код, которому доверяете. Скрипт из случайного репозитория может прочитать ваши ключи из домашней папки или удалить файлы — браузерной «песочницы» здесь нет.

Где применяют Node.js

Node особенно хорош там, где программа много ждёт: ответа базы данных, файла, сети. Пока одна операция ждёт, Node обслуживает другие, поэтому один процесс держит тысячи одновременных соединений. Вот так выглядит минимальный веб-сервер (файл server.mjs):

js
import { createServer } from 'node:http';

const server = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end(`Hello from Node.js ${process.version}!\n`);
});

server.listen(3000, () => {
  console.log('Server is running at http://localhost:3000');
});

Запустите node server.mjs и откройте http://localhost:3000 в браузере — вы увидите Hello from Node.js v24.21.0!. В отличие от hello.js, этот процесс не завершается: сервер ждёт новых запросов, пока вы не нажмёте Ctrl+C. Модуль http подробно разберём в отдельном разделе.

Типичные области применения:

  • API и бэкенды — REST и GraphQL-серверы на Express, Fastify, NestJS.
  • Real-time — чаты, уведомления, совместное редактирование, онлайн-игры на WebSocket и Socket.IO.
  • CLI-утилиты — npm, ESLint, Prettier, TypeScript-компилятор и сотни других инструментов написаны для Node.
  • SSR и фулстек-фреймворки — Next.js, Nuxt, Astro рендерят страницы на сервере с помощью Node.
  • Инструменты сборки — Vite, webpack, Rollup: любой современный фронтенд-проект собирается в Node.
  • Десктоп — Electron (на нём сделан VS Code) объединяет Node и Chromium.

Где Node слаб

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

Типичные ошибки

1. Браузерные объекты в Node. Код с document или window падает сразу:

js
document.querySelector('h1'); // ❌ ReferenceError: document is not defined

В Node нет страницы и DOM. Для глобального объекта используйте globalThis, а код, который работает с DOM, запускайте в браузере.

2. Node-модули во фронтенд-коде. Обратная ситуация: import fs from 'node:fs' в скрипте, подключённом к HTML-странице, не заработает — у браузера нет доступа к файловой системе. Код для сервера и код для браузера живут в разных средах, даже если написаны на одном языке.

3. «Node.js — это фреймворк» или «язык». Node — среда выполнения. Язык — JavaScript (или TypeScript, который компилируется в JavaScript). Фреймворки — Express, Fastify, NestJS — это npm-пакеты, которые работают поверх Node.

4. Тяжёлые вычисления прямо в обработчике запроса. Цикл на несколько секунд в обработчике HTTP-запроса «замораживает» сервер для всех пользователей. Такие задачи выносят в worker threads, очереди фоновых задач или отдельные сервисы.

Итог

  • Node.js — среда выполнения JavaScript вне браузера, а не язык и не фреймворк.
  • Основа Node: движок V8 выполняет JavaScript, libuv отвечает за event loop и асинхронный ввод-вывод, C++-привязки связывают их со стандартной библиотекой.
  • Скрипт запускается командой node файл.js; версии компонентов — в process.version и process.versions.
  • В Node нет window, document и alert, зато есть globalThis, process, Buffer и доступ к файлам, сети и ОС.
  • Многие Web API (fetch, URL, setTimeout, AbortController) работают так же, как в браузере.
  • Node силён в задачах с большим количеством ввода-вывода (API, real-time, CLI, SSR, сборка) и слаб в тяжёлых вычислениях в основном потоке.

Практика

  1. Создайте about.js, который выводит версию Node, версии V8 и libuv, платформу и архитектуру процессора в виде аккуратных строк вида V8: 13.6.233.17-node.53.
  2. Напишите env-check.js, который определяет среду выполнения: если typeof window !== 'undefined', выводит «Browser», если typeof process !== 'undefined' — «Node.js». Запустите его в Node и вставьте тот же код в консоль DevTools браузера.
  3. Напишите system-info.mjs, который собирает объект с платформой, количеством ядер, объёмом свободной памяти в гигабайтах и домашней папкой и сохраняет его в файл system-info.json.
  4. Небольшая задача: доработайте server.mjs так, чтобы по адресу / сервер отвечал приветствием, а по адресу /info — JSON с версией Node, платформой и временем работы процесса (process.uptime()).

💡 В задании 3 пригодятся os.freemem() (байты), JSON.stringify(data, null, 2) и writeFile из node:fs/promises. В задании 4 адрес запроса лежит в req.url, а для JSON отправьте заголовок Content-Type: application/json.