Перейти к основному содержимому

5.01. Справочник по Node.js

Разработчику Архитектору

Справочник по Node.js

1. Глобальные объекты и переменные

Node.js предоставляет ряд глобальных объектов, доступных без импорта.

global

Объект верхнего уровня, аналогичный window в браузере. Все свойства, присвоенные global, становятся глобальными.

global.myVar = 'hello';
console.log(myVar); // 'hello'

process

Объект, содержащий информацию о текущем процессе Node.js и методы для взаимодействия с ним.

Свойства process:

  • process.argv — массив аргументов командной строки.
  • process.env — объект с переменными окружения.
  • process.pid — числовой идентификатор процесса.
  • process.platform — строка с именем платформы (win32, linux, darwin).
  • process.version — версия Node.js (например, 'v20.11.0').
  • process.versions — объект с версиями зависимостей (V8, OpenSSL, zlib и др.).
  • process.execPath — путь к исполняемому файлу Node.js.
  • process.cwd() — текущая рабочая директория.
  • process.arch — архитектура процессора (x64, arm64, ia32).
  • process.release — информация о сборке Node.js (тип, заголовки, исходники).

Методы process:

  • process.exit([code]) — завершает процесс с кодом выхода.
  • process.nextTick(callback[, ...args]) — планирует вызов функции на следующей итерации цикла событий.
  • process.kill(pid[, signal]) — отправляет сигнал процессу.
  • process.chdir(directory) — изменяет текущую рабочую директорию.
  • process.memoryUsage() — возвращает объект с информацией об использовании памяти.
  • process.cpuUsage([previousValue]) — возвращает использование CPU в микросекундах.
  • process.hrtime([time]) — высокоточное измерение времени.
  • process.on(event, listener) — подписка на события (exit, SIGINT, uncaughtException и др.).

console

Объект для вывода информации в терминал.

Методы:

  • console.log()
  • console.info()
  • console.warn()
  • console.error()
  • console.time(label), console.timeEnd(label)
  • console.trace()
  • console.table(data)

Buffer

Глобальный класс для работы с бинарными данными.

Примеры:

const buf = Buffer.from('hello');
const buf2 = Buffer.alloc(10); // 10 байт, заполненных нулями
const buf3 = Buffer.allocUnsafe(10); // неинициализированный буфер

setTimeout, setInterval, setImmediate

Функции таймеров, унаследованные из браузерного JavaScript, но реализованные в Node.js через libuv.

  • setTimeout(callback, delay, ...args)
  • setInterval(callback, delay, ...args)
  • setImmediate(callback, ...args)

Отмена:

  • clearTimeout(timeoutObject)
  • clearInterval(intervalObject)
  • clearImmediate(immediateObject)

__dirname, __filename

Строки с абсолютным путём к текущему файлу и его директории. Доступны только в CommonJS.

В ESM заменяются на:

import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

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

Node.js поставляется с множеством встроенных модулей. Их можно импортировать без установки.

assert

Модуль для написания тестов и проверок.

Основные методы:

  • assert(value, message) — выбрасывает AssertionError, если value ложно.
  • assert.strictEqual(actual, expected)
  • assert.deepStrictEqual(actual, expected)
  • assert.throws(fn, ErrorConstructor)
  • assert.doesNotThrow(fn)

buffer

Работа с бинарными данными. Хотя Buffer глобален, модуль buffer предоставляет дополнительные утилиты.

Свойства:

  • Buffer.poolSize — размер пула для быстрого выделения памяти (по умолчанию 8192 байта).
  • Buffer.isBuffer(obj) — проверка, является ли объект буфером.

child_process

Создание дочерних процессов.

Методы:

  • child_process.spawn(command, [args], [options]) — запуск команды.
  • child_process.exec(command, [options], callback) — выполнение команды с буферизацией вывода.
  • child_process.execFile(file, [args], [options], callback)
  • child_process.fork(modulePath, [args], [options]) — создаёт новый процесс Node.js с IPC-каналом.

Опции:

  • cwd — рабочая директория.
  • env — переменные окружения.
  • stdio — настройка стандартных потоков (['pipe', 'pipe', 'pipe'] по умолчанию).
  • detached — запуск в фоне (Unix).
  • shell — использовать оболочку (/bin/sh, cmd.exe).

События дочернего процесса:

  • close
  • disconnect
  • error
  • exit
  • message

cluster

Модуль для создания нескольких процессов-воркеров, использующих общие порты.

Методы:

  • cluster.isPrimarytrue, если текущий процесс — основной.
  • cluster.isWorkertrue, если текущий процесс — воркер.
  • cluster.fork([env]) — создаёт новый воркер.
  • cluster.workers — объект с активными воркерами.

События:

  • fork
  • online
  • listening
  • disconnect
  • exit
  • setup

console

Уже описан выше как глобальный объект.

crypto

Криптографические функции: хэши, HMAC, шифрование, дешифрование, генерация ключей.

Примеры:

const hash = crypto.createHash('sha256').update('data').digest('hex');
const cipher = crypto.createCipher('aes-192-cbc', key);
const decipher = crypto.createDecipher('aes-192-cbc', key);

Алгоритмы:

  • Хэши: md5, sha1, sha256, sha512
  • Шифрование: aes-128-gcm, aes-192-cbc, chacha20-poly1305
  • Ключи: generateKeyPair, createSecretKey

dgram

Работа с UDP-сокетами.

Методы:

  • dgram.createSocket(type[, callback])type: 'udp4' или 'udp6'.
  • socket.bind(port[, address][, callback])
  • socket.send(msg, offset, length, port, address, callback)
  • socket.close()

События:

  • message
  • listening
  • close
  • error

dns

Разрешение доменных имён.

Методы:

  • dns.lookup(hostname[, options], callback)
  • dns.resolve(hostname[, rrtype], callback)
  • dns.resolve4(hostname, callback)
  • dns.resolve6(hostname, callback)
  • dns.reverse(ip, callback)

Опции lookup:

  • family: 0 (любой), 4 (IPv4), 6 (IPv6)
  • hints: флаги, влияющие на выбор адреса

events

Базовый класс EventEmitter.

Методы:

  • emitter.on(eventName, listener)
  • emitter.once(eventName, listener)
  • emitter.emit(eventName, ...args)
  • emitter.removeListener(eventName, listener)
  • emitter.removeAllListeners([eventName])
  • emitter.listenerCount(eventName)
  • emitter.setMaxListeners(n)

fs (File System)

Работа с файловой системой.

Асинхронные методы (callback-based):

  • fs.readFile(path[, options], callback)
  • fs.writeFile(file, data[, options], callback)
  • fs.appendFile(file, data[, options], callback)
  • fs.unlink(path, callback) — удаление файла
  • fs.mkdir(path[, options], callback)
  • fs.rmdir(path[, options], callback)
  • fs.readdir(path[, options], callback)
  • fs.stat(path, callback) — информация о файле/директории
  • fs.access(path[, mode], callback) — проверка прав доступа
  • fs.copyFile(src, dest[, flags], callback)
  • fs.watch(filename[, options][, listener])
  • fs.watchFile(filename[, options], listener)

Синхронные методы:

  • fs.readFileSync
  • fs.writeFileSync
  • fs.existsSync
  • fs.statSync
  • и так далее — суффикс Sync

Промисы и async/await:

Доступны через fs.promises:

import { promises as fs } from 'fs';
const data = await fs.readFile('file.txt', 'utf8');

Потоковые операции:

  • fs.createReadStream(path[, options])
  • fs.createWriteStream(path[, options])

Опции:

  • encoding — кодировка ('utf8', 'base64', 'binary')
  • flag — режим открытия ('r', 'w', 'a', 'wx', 'ax' и др.)
  • mode — права доступа (например, 0o666)
  • autoClose — автоматически закрывать поток
  • highWaterMark — размер внутреннего буфера

http

Модуль для создания HTTP-серверов и клиентов.

Сервер:

const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});

Методы сервера:

  • server.listen(port, [hostname], [backlog], [callback])
  • server.close([callback])
  • server.address() — возвращает объект { port, family, address }

События сервера:

  • request — при получении запроса
  • connection — при установке TCP-соединения
  • close
  • error

Клиент:

const req = http.request(options, (res) => {
res.on('data', (chunk) => { /* ... */ });
res.on('end', () => { /* ... */ });
});
req.write('data');
req.end();

Опции запроса:

  • host / hostname
  • port
  • path
  • method (GET, POST, и т.д.)
  • headers
  • timeout
  • agent — управление пулом соединений

События клиента:

  • response
  • socket
  • timeout
  • error

https

Расширение http с поддержкой TLS/SSL. Использует те же API, но требует сертификатов.

Пример сервера:

const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, (req, res) => {
res.end('Secure Hello\n');
}).listen(443);

net

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

Сервер:

const server = net.createServer((socket) => {
socket.write('Echo server\r\n');
socket.pipe(socket); // эхо
});
server.listen(8124);

Клиент:

const client = net.createConnection({ port: 8124 }, () => {
client.write('Hello');
});

События:

  • connect
  • data
  • end
  • error
  • close
  • drain — когда буфер отправки освобождается

os

Информация о системе.

Методы:

  • os.arch() — архитектура (x64, arm64)
  • os.cpus() — массив информации о ядрах CPU
  • os.freemem() — свободная память в байтах
  • os.totalmem() — общая память
  • os.homedir() — домашняя директория пользователя
  • os.hostname() — имя хоста
  • os.networkInterfaces() — сетевые интерфейсы
  • os.platform()win32, linux, darwin
  • os.release() — версия ОС
  • os.tmpdir() — временная директория
  • os.uptime() — время работы системы в секундах
  • os.userInfo([options]) — информация о пользователе

path

Работа с путями файловой системы.

Методы:

  • path.join(...paths) — объединяет пути с учётом разделителя ОС
  • path.resolve(...paths) — преобразует в абсолютный путь
  • path.basename(path[, ext]) — имя файла
  • path.dirname(path) — директория
  • path.extname(path) — расширение
  • path.parse(path) — разбивает путь на объект { root, dir, base, name, ext }
  • path.format(pathObject) — обратная операция
  • path.isAbsolute(path) — проверка абсолютности
  • path.relative(from, to) — относительный путь между двумя точками
  • path.normalize(path) — нормализует путь (.., ., двойные слэши)

Свойства:

  • path.sep — разделитель (/ или \)
  • path.delimiter — разделитель переменных окружения (: или ;)

querystring

Парсинг и сериализация query-строк.

Методы:

  • querystring.parse(str[, sep][, eq][, options])
  • querystring.stringify(obj[, sep][, eq][, options])
  • querystring.escape(str)
  • querystring.unescape(str)

Опции:

  • maxKeys — максимальное число параметров
  • decodeURIComponent — функция декодирования значений

stream

Базовая абстракция для потоковой обработки данных.

Типы потоков:

  • Readable — источник данных
  • Writable — приёмник данных
  • Duplex — одновременно читаемый и записываемый (net.Socket)
  • Transform — Duplex с преобразованием (zlib.createGzip())

Методы Readable:

  • read([size])
  • setEncoding(encoding)
  • pause(), resume()
  • pipe(destination[, options])
  • unpipe([destination])

События Readable:

  • data
  • end
  • error
  • close
  • readable

Методы Writable:

  • write(chunk[, encoding][, callback])
  • end([chunk][, encoding][, callback])

События Writable:

  • drain
  • finish
  • error
  • close

timers

Уже частично описан через глобальные setTimeout и др. Дополнительно:

  • timers.setImmediate и timers.clearImmediate — доступны как модуль.
  • timers.promises — версии с промисами:
    import { setTimeout } from 'timers/promises';
    await setTimeout(1000);

tls

Работа с TLS-сокетами (без HTTP).

Создание сервера:

const server = tls.createServer(options, (socket) => {
socket.write('Secure connection\n');
});

Клиент:

const socket = tls.connect(8000, 'localhost', () => {
socket.write('Client hello');
});

tty

Проверка, является ли поток терминалом.

  • tty.isatty(fd) — возвращает true, если файловый дескриптор связан с TTY.
  • process.stdin.isTTY, process.stdout.isTTY — часто используются для определения контекста выполнения.

url

Парсинг и формирование URL.

Методы:

  • url.parse(urlString[, parseQueryString[, slashesDenoteHost]]) — устаревший, но поддерживается.
  • new URL(input[, base]) — современный способ (Web Standard).
  • url.format(urlObject) — обратная операция к parse.
  • url.resolve(from, to) — разрешение относительного URL.

Пример:

const myURL = new URL('https://example.com:8080/path?query=1#frag');
console.log(myURL.hostname); // 'example.com'
console.log(myURL.port); // '8080'
console.log(myURL.searchParams.get('query')); // '1'

util

Утилитарные функции.

Методы:

  • util.inspect(object[, options]) — строковое представление объекта для отладки.
  • util.promisify(fn) — преобразует функцию с callback в промис.
  • util.callbackify(promiseFn) — обратная операция.
  • util.types.isDate(obj), util.types.isRegExp(obj) — точная типизация.
  • util.inherits(constructor, superConstructor) — устаревшее наследование (до ES6 классов).
  • util.format(format[, ...args]) — аналог printf.

Опции inspect:

  • depth — глубина рекурсии
  • colors — цветной вывод
  • showHidden — показывать неперечисляемые свойства
  • compact — компактный вывод

v8

Доступ к внутренним данным движка V8.

Методы:

  • v8.getHeapStatistics() — статистика кучи
  • v8.getHeapSpaceStatistics() — информация о сегментах кучи
  • v8.serialize(value) / v8.deserialize(buffer) — сериализация, совместимая с structured clone algorithm
  • v8.setFlagsFromString(flags) — динамическая настройка флагов V8

vm

Выполнение кода в изолированном контексте.

Пример:

const vm = require('vm');
const sandbox = { x: 1 };
vm.createContext(sandbox);
vm.runInContext('x += 1;', sandbox);
console.log(sandbox.x); // 2

Методы:

  • vm.createContext([sandbox])
  • vm.runInContext(code, contextifiedSandbox[, options])
  • vm.runInNewContext(code[, sandbox][, options])
  • vm.runInThisContext(code[, options])

worker_threads

Многопоточность в Node.js.

Основные элементы:

  • Worker — отдельный поток
  • parentPort — порт для обмена сообщениями
  • workerData — данные, переданные при создании
  • isMainThreadtrue в основном потоке
  • threadId — уникальный ID потока

Пример:

// main.js
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename, { workerData: 42 });
worker.on('message', (msg) => console.log(msg));
} else {
parentPort.postMessage(workerData * 2);
}

zlib

Сжатие и распаковка данных.

Методы:

  • zlib.gzip(buf, callback)
  • zlib.gunzip(buf, callback)
  • zlib.deflate(buf, callback)
  • zlib.inflate(buf, callback)
  • zlib.brotliCompress(buf, callback)
  • zlib.brotliDecompress(buf, callback)

Потоковые версии:

  • zlib.createGzip()
  • zlib.createGunzip()
  • zlib.createDeflate()
  • zlib.createInflate()
  • zlib.createBrotliCompress()
  • zlib.createBrotliDecompress()

3. Параметры командной строки (node --help)

Node.js поддерживает множество флагов при запуске.

Основные флаги:

  • --version / -v — вывод версии
  • --help / -h — справка
  • --eval "code" / -e "code" — выполнить JavaScript-код
  • --print "code" / -p "code" — выполнить и вывести результат
  • --require module / -r module — загрузить модуль до запуска скрипта
  • --input-type=type — указать тип входных данных (module или commonjs) при использовании --eval
  • --loader=specifier — указать custom loader для ESM

Отладка:

  • --inspect[=[host:]port] — включить инспектор (по умолчанию 127.0.0.1:9229)
  • --inspect-brk — пауза при старте
  • --trace-warnings — трассировка предупреждений
  • --trace-deprecation — трассировка устаревших API
  • --throw-deprecation — выбрасывать ошибки вместо предупреждений

Производительность:

  • --max-old-space-size=size — лимит памяти в мегабайтах
  • --no-warnings — отключить все предупреждения
  • --experimental-modules — включить экспериментальные ESM-фичи (в новых версиях не требуется)
  • --conditions=condition — задать условия импорта (для package.json exports)

Переменные окружения:

  • NODE_OPTIONS — передача флагов через переменную окружения
  • NODE_ENV — окружение (production, development)
  • NODE_PATH — дополнительные пути для поиска модулей
  • UV_THREADPOOL_SIZE — размер пула потоков libuv (по умолчанию 4)

4. Структура проекта Node.js

Типичная структура проекта на Node.js включает следующие элементы:

my-node-app/
├── package.json
├── package-lock.json (или yarn.lock, pnpm-lock.yaml)
├── node_modules/
├── src/ # исходный код приложения
│ ├── index.js # точка входа
│ ├── routes/
│ ├── controllers/
│ ├── models/
│ ├── middleware/
│ └── utils/
├── public/ # статические файлы (если есть веб-интерфейс)
├── config/ # конфигурационные файлы
├── tests/ # тесты (unit, integration)
├── scripts/ # вспомогательные скрипты
├── .env # переменные окружения (не в репозитории)
├── .gitignore
├── README.md
└── LICENSE

Рекомендуется разделять логику по слоям: маршрутизация, контроллеры, бизнес-логика, доступ к данным, утилиты. Это упрощает поддержку, тестирование и масштабирование.


5. package.json — полное руководство

Файл package.json описывает проект, его зависимости, скрипты и метаданные.

Обязательные поля:

  • "name" — имя пакета (должно быть уникальным в npm, без заглавных букв и спецсимволов кроме -, _)
  • "version" — версия в формате SemVer (MAJOR.MINOR.PATCH)

Основные поля:

  • "description" — краткое описание
  • "main" — точка входа (по умолчанию index.js)
  • "type" — тип модулей: "commonjs" (по умолчанию) или "module" (включает ESM)
  • "exports" — тонкая настройка экспорта для разных условий (например, import, require, node, browser)
  • "scripts" — команды, запускаемые через npm run <script>
  • "dependencies" — зависимости времени выполнения
  • "devDependencies" — зависимости только для разработки (тесты, сборка)
  • "peerDependencies" — зависимости, которые должны быть установлены в основном проекте (часто в библиотеках)
  • "engines" — требуемые версии Node.js и npm:
    "engines": {
    "node": ">=18.0.0",
    "npm": ">=8.0.0"
    }
  • "files" — список файлов, включаемых при публикации пакета
  • "keywords" — ключевые слова для поиска в npm
  • "author", "contributors", "license", "repository", "homepage"

Пример package.json:

{
"name": "my-api",
"version": "1.2.0",
"description": "REST API on Node.js",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "jest",
"lint": "eslint src/",
"build": "tsc"
},
"dependencies": {
"express": "^4.18.0",
"dotenv": "^16.0.0"
},
"devDependencies": {
"nodemon": "^3.0.0",
"jest": "^29.0.0",
"eslint": "^8.0.0"
},
"engines": {
"node": ">=18.0.0"
},
"license": "MIT"
}

6. Управление зависимостями

Команды npm:

  • npm init — создание package.json
  • npm install / npm i — установка всех зависимостей из package.json
  • npm install <package> — установка и добавление в dependencies
  • npm install <package> --save-dev — установка в devDependencies
  • npm uninstall <package> — удаление пакета
  • npm update — обновление зависимостей в пределах версионных ограничений
  • npm outdated — показ устаревших пакетов
  • npm audit — проверка уязвимостей
  • npm audit fix — автоматическое исправление некоторых уязвимостей

Версионные диапазоны:

  • 1.2.3 — точная версия
  • ~1.2.3 — совместимость с патчами (>=1.2.3 <1.3.0)
  • ^1.2.3 — совместимость с минорными и патчами (>=1.2.3 <2.0.0)
  • * — любая версия (не рекомендуется)
  • latest — последняя опубликованная версия

Файлы блокировки:

  • package-lock.json — фиксирует точные версии всех зависимостей (включая вложенные)
  • Обеспечивает воспроизводимую установку на всех машинах
  • Должен быть включён в систему контроля версий

7. Скрипты в package.json

Скрипты позволяют стандартизировать рабочие процессы.

Примеры:

"scripts": {
"start": "node server.js",
"dev": "NODE_ENV=development nodemon server.js",
"test": "jest --coverage",
"test:watch": "jest --watch",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"build": "webpack --mode production",
"prepublishOnly": "npm test && npm run build"
}

Особые скрипты:

  • prepublishOnly — запускается перед публикацией
  • preinstall, postinstall — до и после установки
  • prestart, poststart — до и после npm start

Переменные окружения в скриптах:

  • Windows: set NODE_ENV=production && node app.js
  • Unix: NODE_ENV=production node app.js
  • Кроссплатформенно: использовать пакет cross-env

8. Обработка ошибок

Node.js использует несколько моделей обработки ошибок:

Callback-стиль:

fs.readFile('file.txt', (err, data) => {
if (err) {
console.error('Ошибка чтения:', err.message);
return;
}
console.log(data.toString());
});

Промисы и async/await:

try {
const data = await fs.promises.readFile('file.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('Ошибка:', err.message);
}

Глобальные обработчики:

process.on('uncaughtException', (err) => {
console.error('Необработанное исключение:', err);
process.exit(1);
});

process.on('unhandledRejection', (reason, promise) => {
console.error('Необработанный промис:', reason);
process.exit(1);
});

Рекомендуется логировать ошибки, очищать ресурсы и завершать процесс в случае критических сбоев.


9. Безопасность

Основные практики:

  • Регулярно обновлять зависимости (npm outdated, npm update)
  • Использовать npm audit и инструменты вроде snyk, dependabot
  • Не коммитить .env и другие секреты
  • Валидировать и санировать все входные данные
  • Использовать helmet в Express-приложениях
  • Ограничивать размеры запросов (body-parser с лимитами)
  • Отключать отладочные эндпоинты в продакшене
  • Использовать HTTPS в продакшене
  • Устанавливать минимально необходимые права для процесса

Защита от распространённых уязвимостей:

  • Prototype Pollution — избегать небезопасного использования Object.assign, lodash.merge
  • Command Injection — не передавать пользовательский ввод напрямую в child_process.exec
  • Path Traversal — нормализовать пути и проверять, что они находятся внутри разрешённой директории:
    const path = require('path');
    const filePath = path.join(__dirname, 'public', userProvidedPath);
    if (!filePath.startsWith(path.resolve(__dirname, 'public'))) {
    throw new Error('Недопустимый путь');
    }

10. CLI-инструменты и отладка

Полезные глобальные пакеты:

  • nodemon — перезапуск приложения при изменении файлов
  • pm2 — продакшен-менеджер процессов
  • http-server — простой статический сервер
  • tsx / esbuild-runner — запуск TypeScript без предварительной компиляции

Встроенная отладка:

  • Запуск с --inspect и подключение через Chrome DevTools (chrome://inspect)
  • Использование debugger; в коде
  • Точки останова в VS Code через launch-конфигурацию

Профилирование:

  • --prof — генерация лога V8 profiler
  • --prof-process — анализ лога
  • Инструменты: Clinic.js, 0x, Chrome DevTools Performance tab

11. Практические шаблоны

Сервер на чистом Node.js:

const http = require('http');
const url = require('url');

const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
if (parsedUrl.pathname === '/hello') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello!' }));
} else {
res.writeHead(404);
res.end('Not Found');
}
});

server.listen(3000, () => console.log('Server running on port 3000'));

Чтение конфигурации:

// config/index.js
const dotenv = require('dotenv');
dotenv.config();

module.exports = {
port: process.env.PORT || 3000,
dbUrl: process.env.DATABASE_URL,
jwtSecret: process.env.JWT_SECRET
};

Логирование:

Использовать специализированные библиотеки: winston, pino, bunyan.
Пример с console (для простых случаев):

const log = (level, message) => {
console.log(`[${new Date().toISOString()}] [${level}] ${message}`);
};

12. Производительность

Основные принципы:

  • Использовать неблокирующие операции
  • Избегать синхронных методов (fs.readFileSync, child_process.execSync) в продакшене
  • Минимизировать количество блокирующих вычислений в основном потоке
  • Использовать кэширование (в памяти, Redis, CDN)
  • Оптимизировать сериализацию/десериализацию JSON
  • Использовать стриминг для больших объёмов данных

Инструменты профилирования:

  • clinic.js — автоматический анализ производительности
  • 0x — генерация flamegraph
  • Node.js built-in profiler — флаги --prof, --prof-process
  • Chrome DevTools — CPU profiling, memory snapshots
  • process.memoryUsage(), process.cpuUsage() — ручной мониторинг

Работа с памятью:

  • Избегать утечек: не хранить ссылки на объекты дольше необходимого
  • Использовать WeakMap, WeakSet для кэшей
  • Ограничивать размеры коллекций
  • Периодически вызывать global.gc() (только при запуске с --expose-gc)

Масштабирование:

  • Кластеризация: cluster модуль для использования всех ядер CPU
  • Микросервисы: разделение логики на независимые сервисы
  • Worker Threads: вынос тяжёлых вычислений в отдельные потоки
  • Очереди задач: Bull, Agenda — для отложенной обработки

13. Работа с базами данных

Node.js поддерживает широкий спектр СУБД через драйверы и ORM.

Реляционные базы:

  • PostgreSQL: pg (node-postgres), Sequelize, TypeORM, Prisma
  • MySQL/MariaDB: mysql2, Sequelize, TypeORM
  • SQLite: better-sqlite3, sqlite3

Пример с pg:

const { Client } = require('pg');
const client = new Client({ connectionString: process.env.DATABASE_URL });
await client.connect();
const res = await client.query('SELECT * FROM users WHERE id = $1', [1]);
await client.end();

NoSQL:

  • MongoDB: mongodb (официальный драйвер), Mongoose
  • Redis: redis — для кэширования, очередей, сессий
  • CouchDB, DynamoDB, Firestore — через соответствующие SDK

Пулы соединений:

Все современные драйверы поддерживают пул соединений. Это критически важно для производительности:

const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // максимальное число соединений
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000
});

Миграции:

  • Использовать инструменты: knex, sequelize-cli, Prisma Migrate
  • Версионировать схему БД вместе с кодом
  • Избегать прямого изменения схемы вручную

14. Тестирование

Уровни тестирования:

  • Unit-тесты — проверка отдельных функций
  • Integration-тесты — взаимодействие модулей
  • E2E-тесты — сквозные сценарии

Фреймворки:

  • Jest — всё в одном: runner, assertions, mocks, coverage
  • Mocha + Chai + Sinon — классический стек
  • Vitest — быстрый альтернативный runner (для ESM)
  • Supertest — тестирование HTTP-серверов

Пример unit-теста:

// math.js
exports.add = (a, b) => a + b;

// math.test.js
const { add } = require('./math');
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});

Пример integration-теста:

const request = require('supertest');
const app = require('./app');

test('GET /users returns 200', async () => {
const res = await request(app).get('/users');
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body)).toBe(true);
});

Покрытие кода:

  • jest --coverage — генерация отчёта
  • Целевой уровень покрытия: 70–90% для критических модулей

CI/CD:

  • Запуск тестов при каждом push в репозиторий
  • Блокировка мержа при падении тестов
  • Использование GitHub Actions, GitLab CI, CircleCI

15. Деплой и эксплуатация

Варианты развёртывания:

  • Собственный сервер (VPS): Ubuntu + Nginx + PM2
  • PaaS: Heroku, Render, Railway, Vercel (для serverless)
  • Контейнеризация: Docker + Kubernetes
  • Serverless: AWS Lambda, Cloudflare Workers (ограниченная совместимость)

Dockerfile пример:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]

PM2 (Process Manager):

npm install -g pm2
pm2 start src/index.js --name "my-app"
pm2 startup # автозапуск при старте системы
pm2 save # сохранить список процессов
pm2 logs my-app # просмотр логов

Обратный прокси:

Nginx перед Node.js:

server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
}

Переменные окружения:

  • Все конфигурационные параметры — через .env или переменные окружения
  • Никаких «магических» значений в коде
  • Использовать dotenv только в разработке

16. Мониторинг и логирование

Логирование:

  • Структурированные логи в формате JSON
  • Уровни: debug, info, warn, error
  • Библиотеки: pino, winston, bunyan
  • Отправка логов в централизованные системы: ELK, Datadog, Sentry

Метрики:

  • Количество запросов в секунду
  • Время ответа (p50, p95, p99)
  • Использование памяти и CPU
  • Количество активных соединений

Алертинг:

  • Настройка оповещений при превышении порогов
  • Интеграция с Slack, Telegram, Email

Инструменты:

  • Prometheus + Grafana — сбор и визуализация метрик
  • New Relic, Datadog — коммерческие APM-системы
  • Sentry — отслеживание ошибок

17. Сравнение с другими средами выполнения

Node.js vs Deno:

  • Deno — безопаснее по умолчанию (требует явных разрешений)
  • Поддержка TypeScript «из коробки»
  • Единый исполняемый файл
  • Модули по URL, без package.json
  • Меньше зрелых библиотек

Node.js vs Bun:

  • Bun — написан на Zig, значительно быстрее в запуске и установке
  • Совместим с большинством npm-пакетов
  • Встроенный bundler, тест-раннер, transpiler
  • Ещё не стабилен для продакшена (на начало 2026 года)

Node.js vs Python (FastAPI/Django):

  • Node.js лучше для I/O-интенсивных задач (чаты, реалтайм)
  • Python предпочтителен для CPU-интенсивных задач (ML, data science)

Node.js vs Go:

  • Go — компилируемый язык, выше производительность и потребление памяти
  • Node.js — быстрее в разработке, богаче экосистема для веба