Собеседование по Node.js начинается с event loop и асинхронного кода, затем переходит к API, обработке ошибок, streams, производительности и безопасности. Чаще всего кандидаты спотыкаются, когда описывают event loop как магию. Чёткое объяснение того, что где выполняется и что блокирует, — именно то, что слушают интервьюеры.
Ниже — 24 вопроса с ответами. Примеры кода короткие, чтобы вы могли набрать их по памяти.
Event loop и асинхронность
1. Что такое Node.js?
Среда выполнения JavaScript, построенная на движке V8 от Chrome, которая работает вне браузера. Она использует однопоточный event loop для JavaScript с неблокирующим I/O, что делает её удобной для обработки множества соединений, которые большую часть времени проводят в ожидании.
2. Как работает event loop?
Код JavaScript выполняется в одном потоке. Когда он запускает операцию ввода-вывода, например чтение файла или запрос, Node передаёт её системе или пулу потоков и продолжает работу. Когда операция завершается, её колбэк ставится в очередь, и event loop выполняет его, когда стек вызовов пуст. Цикл проходит через фазы: timers, pending callbacks, poll (I/O), check (setImmediate) и close callbacks.
3. Каков порядок выполнения process.nextTick, Promises, setTimeout и setImmediate?
console.log('1 sync');
setTimeout(() => console.log('4 timeout'), 0);
setImmediate(() => console.log('5 immediate'));
Promise.resolve().then(() => console.log('3 promise'));
process.nextTick(() => console.log('2 nextTick'));
Синхронный код выполняется первым. Затем колбэки process.nextTick, потом микрозадачи промисов, потом фазы цикла. setTimeout(0) и setImmediate могут вести себя по-разному в главном модуле, но внутри I/O-колбэка setImmediate всегда выполняется первым. Будьте готовы объяснить, а не просто пересказать.
4. Что значит «блокировать event loop» и как этого избежать?
Долгая синхронная задача, например разбор огромного JSON, большой цикл или fs.readFileSync в обработчике запроса, останавливает все остальные запросы, пока не завершится. Избегайте этого, используя асинхронные API, разбивая работу на части или перенося ресурсоёмкие вычисления в worker threads или отдельный процесс.
5. Колбэки, промисы и async/await: в чём разница?
Колбэки — изначальный стиль, который может приводить к глубокой вложенности. Промисы представляют будущее значение и объединяются в цепочки через then. async/await — это синтаксис поверх промисов, который читается как синхронный код и работает с try/catch.
6. Как запускать асинхронные задачи параллельно?
const [user, orders] = await Promise.all([getUser(id), getOrders(id)]);
Promise.all отклоняется, если хотя бы одна задача завершилась ошибкой. Promise.allSettled ждёт все и сообщает результат каждой. Promise.race возвращает первый завершившийся. Не используйте await внутри цикла, когда вызовы независимы.
7. В чём разница между worker threads, дочерними процессами и cluster?
Worker threads выполняют JavaScript в отдельных потоках внутри одного процесса и могут разделять память, что подходит для ресурсоёмких вычислений. Дочерние процессы запускают отдельные программы. Модуль cluster создаёт несколько копий приложения, по одной на ядро, с общим портом, что позволяет задействовать все ядра CPU для обработки запросов.
Модули и инструменты
8. CommonJS против ES-модулей?
CommonJS использует require и module.exports и загружается синхронно. ES-модули используют import и export, являются стандартом в JavaScript и поддерживают top-level await. Node поддерживает оба варианта, выбор определяется расширением файла или полем type в package.json.
9. Что находится в package.json и в чём разница между dependencies и devDependencies?
Он содержит метаданные, скрипты и зависимости. dependencies нужны во время выполнения, а devDependencies — только для разработки и тестирования. Lock-файл фиксирует точные версии, чтобы установки были воспроизводимыми.
10. Как вы работаете с конфигурацией окружения?
Используйте переменные окружения, читайте их через process.env с помощью валидируемого модуля конфигурации. Держите секреты вне репозитория и используйте менеджер секретов в продакшене.
API и Express
11. Что такое middleware в Express?
Функция с доступом к запросу, ответу и next. Middleware выполняется по порядку и может изменять запрос, завершать ответ или передавать управление дальше. Типичные применения — логирование, разбор тела запроса, аутентификация и обработка ошибок.
app.use((req, res, next) => {
console.log(req.method, req.url);
next();
});
12. Как обрабатывать ошибки в приложении на Express?
Перехватывайте ошибки в асинхронных обработчиках и передавайте их в next(err), затем используйте middleware для обработки ошибок с четырьмя аргументами (err, req, res, next), чтобы отправлять единообразный ответ. В Express 5 отклонённые промисы из обработчиков передаются автоматически. Для необработанных исключений и необработанных отклонений промисов логируйте и перезапускайте процесс, а не продолжайте работу в неизвестном состоянии.
13. Как бы вы спроектировали endpoint REST API для создания заказа?
Проверьте входные данные, аутентифицируйте пользователя, проверьте права, создайте заказ внутри транзакции базы данных, верните 201 с новым ресурсом и его location, обрабатывайте дубликаты с помощью ключа идемпотентности и возвращайте понятные ошибки с корректными статус-кодами.
14. Как вы аутентифицируете пользователей?
Сессии с cookie или токены, например JWT. Хешируйте пароли медленным алгоритмом, таким как bcrypt или argon2. С JWT держите срок действия коротким, осторожно используйте refresh-токены и не храните в токене конфиденциальные данные.
Потоки, файлы и производительность
15. Что такое потоки и зачем их использовать?
Потоки обрабатывают данные порциями, а не загружают всё в память целиком. Бывают читаемые, записываемые, дуплексные и трансформирующие потоки. Используйте их для больших файлов, загрузки и скачивания.
const fs = require('node:fs');
const { pipeline } = require('node:stream/promises');
const zlib = require('node:zlib');
await pipeline(fs.createReadStream('in.log'), zlib.createGzip(), fs.createWriteStream('in.log.gz'));
16. Что такое backpressure?
Когда записываемый поток не успевает за читаемым, он даёт источнику сигнал замедлиться. pipeline и pipe делают это за вас. Если пишете вручную, проверяйте возвращаемое значение write() и дожидайтесь события drain.
17. Как найти утечку памяти?
Следите за памятью во времени, снимайте снимки кучи (Chrome DevTools или --inspect) и сравнивайте их, чтобы увидеть, какие объекты растут. Частые причины — глобальные кэши без срока жизни, непрошеные слушатели событий и замыкания, удерживающие большие объекты.
18. Как масштабировать приложение на Node.js?
Запустите несколько процессов через модуль cluster или менеджер процессов, поставьте их за балансировщик нагрузки, сделайте приложение stateless, перенеся сессии в Redis или базу данных, используйте кэширование и масштабируйтесь контейнерами. Тяжёлые вычисления выносите в воркеры или отдельные сервисы.
19. Как профилировать медленный эндпоинт?
Сначала измерьте — логи и замеры времени, затем --prof или --cpu-prof, либо инструмент для flame-графов, чтобы найти горячие функции. Проверьте запросы к базе: медлительность чаще прячется там, а не в JavaScript.
Безопасность и надёжность
20. Какие бывают типичные проблемы безопасности в Node.js?
Инъекции (SQL, NoSQL, командные), межсайтовый скриптинг, слабая аутентификация, уязвимые зависимости, секреты в коде, отсутствие ограничения частоты запросов и небезопасная десериализация. Защищайтесь валидацией входных данных, параметризованными запросами, helmet, аудитом зависимостей (npm audit) и принципом наименьших привилегий.
21. Как корректно завершить работу?
По SIGTERM перестаньте принимать новые соединения, дайте текущим запросам завершиться, закройте соединения с базой данных и выходите, а на случай зависания предусмотрите таймаут.
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
});
22. Как тестировать код на Node.js?
Юнит-тесты с раннером вроде встроенного node:test, Jest или Vitest, с моками внешних вызовов. Интеграционные тесты против тестовой базы и HTTP-тесты с инструментом вроде Supertest. Держите тесты быстрыми и независимыми.
Проектирование и сценарии
23. Ваш API тормозит под нагрузкой. Как вы будете разбираться?
Посмотрите метрики задержки и загрузки CPU. Если CPU высокий на одном ядре, ищите блокирующий код или тяжёлую работу с JSON. Если CPU низкий, а задержка высокая — смотрите на ожидание базы данных или других сервисов. Затем добавьте кэширование, индексы, пул соединений или батчинг и протестируйте снова под нагрузкой.
24. Как бы вы сделали эндпоинт для загрузки больших файлов?
Стримьте загрузку сразу в хранилище, например в объектное хранилище по pre-signed URL, вместо буферизации в памяти. Задайте лимиты размера, проверяйте тип, при необходимости сканируйте и обрабатывайте потом в фоновой задаче.
Как готовиться
Напишите небольшой API с аутентификацией, базой данных и маршрутом загрузки файлов, затем профилируйте его инструментом нагрузки и исправьте одну проблему. Потренируйтесь рисовать event loop и объяснять вывод небольшого скрипта вроде того, что выше. Подготовьте одну реальную историю о том, как вы отлаживали проблему производительности или надёжности. Для секций по коду смотрите наш гайд по ассистенту для собеседований по программированию, а для проектирования — гайд по system design.
Проговаривайте ответы вслух и перечитывайте расшифровку, чтобы найти места, где вы использовали термин, не объяснив его. Соблюдайте правила работодателя насчёт AI-инструментов на любом живом собеседовании.
Практикуйте ответы для собеседования по Node.js с YesToTheOffer
Пройдите mock-техническое собеседование, объясните цикл событий вслух и просмотрите расшифровку afterward. 30 бесплатных минут, без подписки.



