Node.js - серверный JavaScript
Бэкенд — это совокупность программно-аппаратных средств, скрытых от непосредственного восприятия пользователя, которая отвечает за внутреннюю логику работы приложения, обработку данных, взаимодействие с базами данных и внешними сервисами, а также за обеспечение безопасности и масштабируемости. В контексте веб-разработки бэкенд представляет собой серверную часть, которая принимает запросы от клиентской стороны (фронтенда), выполняет необходимые вычисления, обращается к хранилищам данных и возвращает сформированный ответ, часто в формате JSON или HTML. Бэкенд не занимается отрисовкой интерфейса, но определяет, как приложение функционирует под капотом, управляя бизнес-правилами, аутентификацией, авторизацией и производительностью системы. Он может быть написан на различных языках программирования, таких как Python, Java, Ruby, PHP или JavaScript, и его архитектура может варьироваться от монолитной до микросервисной. Ключевой задачей бэкенда является обеспечение надежной, безопасной и быстрой работы приложения для тысяч или миллионов одновременных пользователей.
Сервер — это физический или виртуальный компьютер, выделенный для выполнения специализированных задач, связанных с управлением сетевыми ресурсами, хранением данных и обработкой запросов от других устройств, которые в данном контексте называются клиентами. В широком смысле сервером называют как аппаратное обеспечение, так и программное обеспечение, которое функционирует в режиме ожидания входящих соединений и предоставляет определенные услуги, будь то веб-страницы, файлы, электронная почта или базы данных. Сервер характеризуется высокой надежностью, производительными компонентами и постоянной работой, поскольку он должен быть доступен круглосуточно. В программном понимании сервер — это процесс, который запущен на операционной системе и прослушивает определенные сетевые порты, ожидая запросов по протоколам HTTP, HTTPS, FTP, SSH и другим. Сервер может обслуживать один сайт или приложение, а может быть сконфигурирован для хостинга множества различных сервисов одновременно, используя виртуализацию или контейнеризацию.
Веб-сервер — это конкретный тип серверного программного обеспечения, предназначенный для обработки входящих HTTP-запросов от клиентских приложений, таких как веб-браузеры или мобильные приложения, и возврата им соответствующих HTTP-ответов, чаще всего в виде веб-страниц, стилей, скриптов или данных API. Веб-сервер выполняет роль посредника между клиентом и серверной логикой, умея интерпретировать URL-адреса, метод запроса (GET, POST, PUT, DELETE) и заголовки, а также направлять запросы к статическим файлам или динамическим обработчикам. К классическим примерам веб-серверов относятся Apache HTTP Server, Nginx, Microsoft IIS, а также встроенные серверы в средах разработки, например, в Node.js. Помимо простой отдачи файлов, современные веб-серверы обеспечивают сжатие данных, балансировку нагрузки, кеширование, защиту от DDoS-атак и поддержку шифрования через TLS/SSL. Веб-сервер может выступать как самостоятельным решением для статических сайтов, так и в качестве прокси-сервера перед более тяжелыми приложениями, перенаправляя динамические запросы к специализированным серверам приложений.
Node.js
JavaScript в браузере ограничен песочницей. Node.js — программа, которая выполняет JS на сервере или в CLI — сеть, файлы, процессы, криптография. Один язык на фронте (React) и в API (Express) ускоряет обучение и работу команды.
Рекомендуемый порядок: первая программа → эта статья (устройство runtime) → npm и структура проекта → встроенные модули → Express → Fullstack.
Маршрут по разделу Node.js
| № | Тема | Статья |
|---|---|---|
| 1 | Первая программа, Express API | Первая программа на Node.js |
| 2 | Runtime, event loop, модули | вы здесь |
| 3 | npm: install, scripts, audit | npm — команды, зависимости и lock-файлы |
| 4 | Папки, package.json, env | Структура Node-проекта и правила разработки |
| 5 | fs, http, потоки | Встроенные модули Node.js — fs, потоки и http |
| 6 | Express: middleware, CORS | Express — middleware, маршруты и ошибки |
| 7 | CLI, Docker, production | CLI Node.js — запуск, отладка и деплой |
| 8 | API + фронт | Fullstack на JavaScript — API и фронтенд |
| — | Шпаргалка API | Справочник по Node |
Что такое Node.js
Node.js — это кроссплатформенная среда выполнения с открытым исходным кодом, построенная на движке V8 от Google, которая позволяет выполнять код на языке JavaScript вне браузера, то есть на стороне сервера или в системных скриптах. Node.js была создана Райаном Далем в 2009 году с целью решения проблемы масштабируемости сетевых приложений, и её главной особенностью является асинхронная, управляемая событиями архитектура, которая делает её невероятно эффективной для ввода-выводных операций. Эта среда предоставляет разработчикам унифицированный стек технологий, поскольку один и тот же язык используется и на клиенте, и на сервере, что упрощает разработку и обмен кодом. Node.js не является ни языком программирования, ни фреймворком, а скорее платформой, которая включает в себя набор встроенных модулей для работы с файловой системой, сетью, операционной системой и криптографией. Благодаря своей легковесности и высокой производительности Node.js широко применяется для создания быстрых и масштабируемых веб-приложений, API-сервисов, чат-приложений, стриминговых сервисов и инструментов командной строки.
Node.js — среда выполнения JavaScript вне браузера: движок V8 (как в Chrome) плюс привязки к ОС через libuv. Сильная сторона платформы — I/O-bound нагрузка: много одновременных соединений при умеренном расходе RAM. Долгие вычисления в одном потоке лучше выносить в worker_threads или отдельный сервис.
Среда выполнения — это программное окружение, которое обеспечивает исполнение программного кода, написанного на определенном языке программирования, предоставляя ему доступ к системным ресурсам, библиотекам и управляя жизненным циклом процессов. В отличие от компиляции в машинный код, среда выполнения интерпретирует или выполняет байт-код, управляя памятью, сборкой мусора, потоками и обработкой исключений. Для JavaScript такой средой вне браузера является Node.js, а в браузере — сам движок браузера, который включает в себя интерпретатор JavaScript и Web API. Среда выполнения включает в себя не только движок для выполнения языка, но и набор стандартных объектов, методов и утилит, которые позволяют программе взаимодействовать с внешним миром, например, читать файлы, отправлять сетевые запросы или выводить данные в консоль. Она абстрагирует разработчика от низкоуровневых особенностей операционной системы, предоставляя единый и предсказуемый интерфейс для работы с железом, памятью и процессами ввода-вывода. Разные среды выполнения могут предлагать различные модели конкурентности, что критически влияет на архитектуру и производительность приложений.
Проверка установки:
node -v
npm -v
Минимальный сервер на встроенном http (разбор построчно — Встроенные модули Node.js — fs, потоки и http):
const { createServer } = require('node:http');
const hostname = '127.0.0.1';
const port = 3000;
const server = createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
node server.js
Скачать LTS: nodejs.org. Несколько версий на одной машине — nvm (см. ниже).
История
Райан Даль выпустил Node.js в 2009 году, предложив event loop и неблокирующий I/O вместо модели "поток на каждый запрос". С появлением npm (2010) выросла крупнейшая экосистема пакетов для одного языка. С 2015 года идут параллельные линии LTS (долгая поддержка, обычно 30+ месяцев) и Current (свежие возможности). Для production берите LTS.
Event Loop — это фундаментальный механизм асинхронного программирования, который лежит в основе работы Node.js и всех JavaScript-движков в браузерах, представляющий собой бесконечный цикл, который постоянно проверяет, не накопились ли новые события или задачи, и выполняет их в порядке очереди. Суть event loop заключается в том, что он позволяет выполнять неблокирующие операции ввода-вывода, несмотря на то, что JavaScript является однопоточным языком, делегируя тяжелые задачи операционной системе или внутренним библиотекам, а затем возвращая результат в виде колбэка в очередь. Этот цикл последовательно обрабатывает несколько фаз, включая выполнение синхронного кода, обработку колбэков из очереди микрозадач (например, промисы) и макрозадач (таймеры, сетевые события), всегда отдавая приоритет микрозадачам перед макрозадачами. Благодаря event loop Node.js может обслуживать десятки тысяч одновременных соединений на одном потоке, не создавая новый поток под каждое соединение, что радикально сокращает накладные расходы на переключение контекста. Понимание работы event loop критически важно для предотвращения блокировки цикла тяжелыми синхронными операциями, которые могут парализовать работу всего приложения, сделав его недоступным для других клиентов.
Неблокирующий I/O — это парадигма ввода-вывода, при которой вызов функции для чтения или записи данных не приостанавливает выполнение программы до завершения операции, а возвращает управление немедленно, позволяя процессору заниматься другими задачами, пока операционная система выполняет запрошенное действие в фоновом режиме. В контексте Node.js неблокирующий I/O означает, что операции с файловой системой, сетевые запросы или обращения к базам данных не тормозят главный поток выполнения, а запускаются асинхронно, и по их завершении в очередь событий помещается соответствующий колбэк или разрешается промис. Это достигается благодаря использованию системных вызовов, таких как epoll, kqueue или IOCP, которые позволяют ядру операционной системы уведомлять приложение о готовности данных, а не ждать их пассивно. Такой подход принципиально отличается от синхронного, блокирующего ввода-вывода, где каждый запрос требует отдельного потока, что приводит к огромным издержкам при большом количестве параллельных подключений. Неблокирующий I/O является краеугольным камнем высокой производительности Node.js, позволяя одному процессу обрабатывать тысячи одновременных соединений без значительного увеличения потребления памяти и ресурсов процессора.
LTS — это аббревиатура от Long-Term Support, то есть «долгосрочная поддержка», которая обозначает стабильную версию программного обеспечения, преимущественно Node.js, для которой производитель гарантирует исправление критических ошибок и уязвимостей в течение продолжительного периода времени, обычно до трех лет. Версии LTS проходят более строгое тестирование и стабилизацию по сравнению с текущими релизами и рекомендуются для использования в производственных средах, где приоритетом является надежность и безопасность, а не новые экспериментальные функции. Каждая четная версия Node.js (например, 14.x, 16.x, 18.x, 20.x) становится LTS после периода активной разработки, проходя через стадии «текущая» и «активная LTS», прежде чем перейти в фазу «поддержки обслуживания». Выбор LTS версии означает, что разработчики могут полагаться на стабильный API и получать критические обновления без риска внезапных изменений, ломающих существующее приложение. Для крупных предприятий и проектов с длительным жизненным циклом использование LTS является стандартом индустрии, позволяющим планировать обновления в четко определенные промежутки времени.
Current — это обозначение для последней, самой свежей версии Node.js, которая находится в активной разработке и содержит новейшие функции, улучшения движка V8 и экспериментальные возможности, еще не прошедшие полный цикл стабилизации. Версии с пометкой Current выпускаются каждые полгода и имеют нечетный номер (например, 17.x, 19.x, 21.x), и они предназначены в первую очередь для разработчиков, которые хотят опробовать новинки языка и среды, а также для авторов библиотек, которым необходимо адаптировать свой код под грядущие изменения. Эти версии не рекомендуются для использования в производственных средах, поскольку они могут содержать нестабильные API, изменения, нарушающие обратную совместимость, или невыявленные ошибки. Период поддержки текущей версии ограничен примерно восемью месяцами, после чего она либо прекращает свое существование, либо, если она четная, трансформируется в версию LTS. Использование Current версий оправдано в разработке, тестировании и для личных проектов, где важны инновации, но для критически важных бизнес-приложений переход на Current обычно откладывается до выхода стабильного LTS-релиза.
Архитектура — event loop
Libuv — это высокопроизводительная многоплатформенная библиотека на языке C, которая является основой асинхронного ввода-вывода в Node.js и берет на себя реализацию цикла событий, абстрагируя различия между операционными системами, такими как Windows, Linux и macOS. Именно libuv предоставляет пул потоков для выполнения блокирующих системных вызовов, а также управляет сетевыми сокетами, таймерами, сигналами и межпроцессным взаимодействием, обеспечивая единообразный API поверх таких механизмов, как IOCP на Windows и epoll/kqueue на Unix-подобных системах. Библиотека не только реализует сам event loop, но и предоставляет функции для работы с файловыми операциями, DNS-запросами и дочерними процессами, при этом все эти операции выполняются асинхронно, не блокируя основной поток JavaScript. Разработчику Node.js не приходится взаимодействовать с libuv напрямую, так как она полностью скрыта за абстракцией встроенных модулей, но именно эта библиотека обеспечивает ту самую неблокирующую магию, благодаря которой Node.js способен выдерживать высокие нагрузки. Помимо Node.js, libuv используется и в других проектах, например, в Julia или в системах, связанных с Luvit, что подтверждает её надежность и универсальность как кросс-платформенного решения для асинхронного программирования.
Сердце Node — цикл событий на libuv:
- JS вызывает, например,
fs.readFile()— задача уходит в пул потоков libuv. - Основной поток не ждёт — выполняет следующий JS.
- По завершении I/O колбэк попадает в очередь; event loop вызывает его в V8.
Так достигается высокая пропускная способность при сетевых и файловых операциях. Синхронные API (readFileSync) и долгий CPU-код в одном потоке блокируют весь сервер — для вычислений используйте worker_threads или вынос в отдельный сервис.
Подробнее про fs, потоки и http — Встроенные модули Node.js — fs, потоки и http.
Принципы платформы
Ядро намеренно небольшое — сеть, файлы и процессы есть в стандартной библиотеке, а фреймворки и ORM живут в npm. Пакеты обычно делают одну задачу, I/O по умолчанию асинхронный (*Sync — исключение для скриптов и редких случаев). Один язык на фронте и в API упрощает общие типы, особенно с TypeScript.
Встроенные модули, с которыми вы столкнётесь чаще всего — fs, http/https, stream, child_process, crypto, os, path, worker_threads.
Установка
Официальный установщик (Windows .msi, macOS .pkg, Linux через NodeSource) — node и npm в PATH.
nvm (macOS/Linux) — несколько версий Node:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install --lts
nvm use --lts
В корне проекта файл .nvmrc с версией (20) — nvm use без аргументов. На Windows — nvm-windows.
Глобальные объекты
Глобальные объекты — это встроенные объекты, доступные в любом месте программы на JavaScript без необходимости их импорта или объявления, которые предоставляют базовую функциональность, такую как работа с числами, строками, массивами, датами, математическими вычислениями и обработкой ошибок. В среде Node.js глобальными объектами являются, например, глобальный объект global, который служит контейнером для всех глобальных переменных, а также такие объекты как console для вывода в терминал, process для управления текущим процессом и получения информации о системе, Buffer для работы с бинарными данными и setTimeout с setInterval для создания таймеров. Важно отличать глобальные объекты браузера, такие как window, от Node.js-объектов, поскольку window в серверной среде отсутствует, а вместо него используется объект global, хотя в современных реализациях на базе ES-модулей доступ к глобальной области также осуществляется через globalThis. Эти объекты предоставляют критически важную инфраструктуру для взаимодействия с операционной системой, управления памятью и обработки исключений, и они являются первой линией API для любого Node.js-приложения. Их использование должно быть осознанным, поскольку загрязнение глобальной области переменными может привести к трудноуловимым ошибкам и конфликтам имен в сложных проектах.
| Объект | Назначение |
|---|---|
global | Корень глобального контекста (аналог window) |
process | argv, env, cwd(), сигналы, exit() |
console | log / error / time — stderr vs stdout важен для логов |
Buffer | Бинарные данные |
__dirname, __filename | Путь модуля (только CommonJS) |
setTimeout, setInterval, setImmediate | Таймеры в фазах event loop |
Пример process:
console.log(process.env.NODE_ENV);
console.log(process.argv.slice(2));
Модули — CommonJS и ESM
Модули — это механизм организации кода в независимые, самодостаточные фрагменты, каждый из которых инкапсулирует определенную функциональность, скрывает внутреннее состояние и предоставляет наружу четко определенный интерфейс для использования в других частях приложения. В контексте Node.js модули позволяют разбивать огромные программы на маленькие, управляемые файлы, что упрощает разработку, тестирование, поддержку и повторное использование кода, а также управление зависимостями через систему пакетов npm. Каждый модуль в Node.js имеет свою собственную область видимости, то есть переменные и функции, объявленные в одном модуле, по умолчанию не видны в других, если они явно не экспортированы с помощью специальных ключевых слов, таких как module.exports или export. Модули могут быть как встроенными, то есть поставляемыми вместе с Node.js (например, fs, http, path), так и сторонними, устанавливаемыми через менеджер пакетов, а также пользовательскими, написанными разработчиком для конкретного проекта. Система модулей в Node.js исторически развивалась от синхронной модели CommonJS к более современной и асинхронной модели ECMAScript Modules, что отражает эволюцию экосистемы и потребностей разработчиков в области оптимизации загрузки и работе с циклическими зависимостями.
CommonJS — это стандарт модульности, который был изначально принят в Node.js и до сих пор остается доминирующим способом организации кода в этой экосистеме, использующий синхронный подход к загрузке зависимостей через функцию require и экспорт сущностей через объект module.exports. В системе CommonJS каждый файл интерпретируется как отдельный модуль, и при вызове require модуль загружается и выполняется немедленно, причем результат его выполнения кешируется для последующих импортов, что гарантирует эффективность и предотвращает многократное выполнение одного и того же кода. Синхронный характер загрузки делает CommonJS удобным для использования на сервере, где файлы читаются с локального диска практически мгновенно, но он не подходит для браузеров без сборщиков, так как блокирующая загрузка неэффективна в сетевой среде. Благодаря динамической природе require, в CommonJS можно импортировать модули условно, внутри функций или в циклах, что дает большую гибкость, но усложняет статический анализ и оптимизацию сборщиками. Несмотря на появление более современных стандартов, CommonJS остается прочной основой для огромного количества библиотек и фреймворков, и знание его синтаксиса обязательно для любого разработчика на Node.js.
ESM — это аббревиатура от ECMAScript Modules, официального стандарта модульности, встроенного непосредственно в спецификацию языка JavaScript, который использует ключевые слова import и export и предлагает асинхронную, статическую модель загрузки зависимостей в отличие от синхронной системы CommonJS. ESM позволяет браузерам и современным средам выполнения, включая Node.js начиная с версии 12, загружать модули асинхронно, что критически важно для веб-сред, и обеспечивает более строгую структуру, поскольку все импорты и экспорты должны быть определены на верхнем уровне, что способствует лучшей оптимизации и процессу tree-shaking — удалению неиспользуемого кода. В Node.js файлы с расширением .mjs по умолчанию интерпретируются как ESM, а .cjs — как CommonJS, хотя можно использовать поле "type": "module" в package.json для смены поведения по умолчанию. ESM поддерживает как именованные экспорты, так и экспорты по умолчанию, а также позволяет делать динамический импорт через функцию import(), которая возвращает промис и открывает возможности для ленивой загрузки кода. Переход на ESM в экосистеме Node.js идет постепенно, и многие современные библиотеки публикуются одновременно в обоих форматах, предоставляя разработчикам возможность выбора в зависимости от их потребностей и инструментов сборки.
CommonJS (исторически по умолчанию):
// math.cjs
const add = (a, b) => a + b;
module.exports = { add };
const { add } = require('./math.cjs');
ES Modules — стандарт JS: import / export. Включение: "type": "module" в package.json или расширение .mjs.
export const add = (a, b) => a + b;
import { add } from './math.js';
| CommonJS | ESM | |
|---|---|---|
| Загрузка | Синхронная | Статический анализ |
| В Node по умолчанию | без "type": "module" | с "type": "module" |
| Смешивание | import() из CJS | default-обёртка при импорте CJS |
Зависимости и node_modules — npm — команды, зависимости и lock-файлы. Структура проекта — Структура Node-проекта и правила разработки.
Фреймворки поверх http
| Express | Fastify | NestJS | |
|---|---|---|---|
| Стиль | Гибкий, middleware | Скорость, JSON Schema | Модули, DI, TypeScript |
| Когда | MVP, обучение, legacy | High-load API | Крупные команды |
Middleware — это программный слой или функция-посредник, которая перехватывает входящие запросы или исходящие ответы в процессе обработки HTTP-транзакции, выполняя определенные действия до того, как запрос достигнет конечного обработчика, или после того, как ответ уже сформирован. В контексте веб-фреймворков, таких как Express.js для Node.js, middleware представляет собой функцию, имеющую доступ к объектам запроса (request) и ответа (response), а также к функции next, вызываемой для передачи управления следующему промежуточному слою в цепочке. Это позволяет последовательно применять множество middleware для решения сквозных задач, таких как логирование, аутентификация пользователей, парсинг тела запроса, сжатие данных, обработка сессий, установка заголовков безопасности и обработка ошибок, не загромождая основную бизнес-логику. Middleware может быть как глобальным, применяемым ко всем маршрутам, так и локальным, привязанным к конкретному пути или методу HTTP, что дает тонкий контроль над обработкой каждого конкретного эндпоинта. Эта архитектурная концепция способствует созданию модульных, гибких и легко расширяемых приложений, поскольку новые функции можно добавлять путем простого включения дополнительных middleware-компонентов без изменения существующего кода.
Учебный путь начинается с Express — Первая программа на Node.js, Express — middleware, маршруты и ошибки. Сравнение и production-паттерны — CLI Node.js — запуск, отладка и деплой.
Node.js и база данных
Серверный JS почти всегда связан с хранилищем: HTTP → Express → service → pool (pg) → PostgreSQL. Запросы к БД асинхронные — event loop продолжает принимать соединения.
Практики: один Pool на процесс, секреты в process.env, graceful shutdown (server.close() → pool.end()), параметризованные запросы $1, $2.
Интерактив ниже — REST, CRUD, пул соединений и связь с event loop.
Play ITЗагрузка интерактивного демо…
Пошаговый код REST + PostgreSQL в учебнике — блоки в Первая программа на Node.js и раздел "Практикум" в исторической версии материала; слои routes / models — Структура Node-проекта и правила разработки.
Как мыслить о Node в production
Production — это среда эксплуатации или окружение, в котором программное обеспечение работает в реальных условиях, обслуживая конечных пользователей и обрабатывая реальные данные, что является финальной стадией жизненного цикла приложения после этапов разработки, тестирования и предпроизводственного этапа. В контексте веб-приложений и Node.js среда production характеризуется акцентом на производительность, стабильность, безопасность и отказоустойчивость, что подразумевает использование оптимизированных настроек, таких как отключение отладочной информации, минификация кода, агрессивное кеширование, использование переменных окружения для конфиденциальных данных и подключение к мощным базам данных и серверам. В production версия Node.js обычно запускается с флагом NODE_ENV=production, что заставляет многие библиотеки работать в более эффективном режиме, исключая лишние проверки и вывод предупреждений, а также активируя кеширование модулей. Развертывание в production требует тщательного планирования, мониторинга, логирования ошибок, настройки балансировщиков нагрузки и механизмов восстановления после сбоев, поскольку любые проблемы в этом окружении напрямую влияют на пользовательский опыт и репутацию бизнеса. Именно для production рекомендуется использовать LTS-версии Node.js, прошедшие длительное тестирование и поддерживаемые обновлениями безопасности.
Чеклист перед production (подробнее — CLI Node.js — запуск, отладка и деплой):
- единая версия Node (
.nvmrc,engines); npm ciв CI, lock в Git;- структурированные логи и единый формат ошибок API;
GET /health, graceful shutdown;- секреты только в переменных окружения.
Практика и ссылки
- Первая программа на Node.js
- npm · Структура проекта · Встроенные модули
- Express · Fullstack
- Next.js
- Electron
Базовый разбор HTTP и HTTPS — HTTP как основа веб-интеграций.