Вопросы на собеседовании: Node.js-разработчик
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Junior Node.js-разработчик.
Смотреть пример резюме: Node.js-разработчик →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
Node.js представляет собой среду выполнения JavaScript вне браузера.
- Он использует движок V8 для компиляции и выполнения JavaScript.
- Он предоставляет серверные API для файлов, сети, процессов и взаимодействия с операционной системой.
- Его событийная модель с неблокирующим вводом-выводом подходит сервисам с множеством одновременных I/O-операций.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы Node.js как среду выполнения, а не язык или фреймворк.
V8 выполняет JavaScript, а libuv предоставляет event loop и кроссплатформенную поддержку асинхронного ввода-вывода.
- V8 разбирает, компилирует, оптимизирует и выполняет JavaScript-код.
- libuv координирует таймеры, готовность сетевых операций и работу, переданную в пул потоков.
- Node.js связывает эти компоненты с JavaScript API, такими как fs, timers и сетевые модули.
Зачем это спрашивают: Сильный ответ разделяет выполнение JavaScript и инфраструктуру ввода-вывода с event loop.
Это означает, что один поток event loop обычно выполняет JavaScript callbacks процесса по одному.
- Одновременные I/O-операции всё равно могут продвигаться через операционную систему и libuv.
- Часть файловых, DNS, crypto и compression операций использует thread pool libuv.
- Worker threads или child processes при необходимости дают дополнительные потоки или процессы выполнения JavaScript.
Зачем это спрашивают: Интервьюер проверяет, отличаете ли вы однопоточное выполнение JavaScript от общей конкурентности runtime.
Event loop это механизм, который последовательно выполняет готовые callbacks и координирует асинхронную работу без блокировки на каждой операции.
- JavaScript запускает работу вроде таймера или сетевого запроса и регистрирует продолжение после её готовности.
- Node.js обрабатывает очереди callbacks в определённых фазах.
- Долгий синхронный JavaScript задерживает остальные callbacks, потому что поток event loop не может выполнять их одновременно.
Зачем это спрашивают: Сильный ответ связывает асинхронные операции, очереди callbacks и цену блокировки основного потока.
Основные фазы это timers, pending callbacks, внутренние idle и prepare, poll, check и close callbacks.
- Фаза timers запускает готовые callbacks setTimeout и setInterval.
- Poll получает I/O-события и запускает многие I/O callbacks, а check запускает callbacks setImmediate.
- На фазе close callbacks обрабатываются события закрытия, например закрытие сокета, а microtasks выполняются вокруг callbacks и не являются обычной фазой.
Зачем это спрашивают: Интервьюер оценивает, понимаете ли вы event loop как набор фаз с очередями, а не одну общую очередь callbacks.
Фаза timers делает callback доступным после истечения задержки, но не гарантирует точное время выполнения.
- Задержка является минимальным порогом, а не назначенным моментом по часам.
- Предыдущая синхронная работа и другие callbacks в очередях могут отложить запуск.
- setInterval повторяет готовность через интервал, но его callbacks также задерживаются при нагрузке на event loop.
Зачем это спрашивают: Сильный ответ не считает JavaScript-таймеры точным планированием реального времени.
Фаза poll получает новые I/O-события и запускает готовые callbacks для многих завершённых I/O-операций.
- Она может ждать I/O, если callbacks пока не готовы и правила планирования не требуют перейти дальше.
- На время ожидания влияют таймеры и callbacks setImmediate в очереди.
- Не каждое асинхронное API завершается в poll, поэтому остальные фазы event loop тоже важны.
Зачем это спрашивают: Интервьюер проверяет понимание poll как основной I/O-фазы без ошибочного отнесения к ней всех callbacks.
setImmediate планирует callback для фазы check, а setTimeout для фазы timers после минимальной задержки.
- Их относительный порядок в коде верхнего уровня нельзя считать общей гарантией.
- Если оба вызова запланированы из одного I/O callback, setImmediate выполняется в ближайшей фазе check раньше таймера с нулевой задержкой.
- Выбирайте API по нужной фазе, а не считайте любой из них командой выполнить немедленно.
Зачем это спрашивают: Сильный ответ называет фазы и не даёт чрезмерно упрощённого обещания порядка.
process.nextTick ставит callback на выполнение после текущей JavaScript-операции и до продолжения event loop в другой фазе.
- После завершения обычного callback Node.js очищает очередь nextTick перед Promise microtasks.
- Выполнение ESM и уже начатая обработка microtasks не позволяют считать это универсальной гарантией порядка исходного кода.
- Рекурсивное планирование nextTick может задержать таймеры и I/O, поэтому оно не заменяет обычное асинхронное планирование.
Зачем это спрашивают: Интервьюер оценивает, знаете ли вы приоритет nextTick и риск задержки остальных задач цикла событий.
Promise reactions выполняются из очереди microtasks после текущего callback или script и до продолжения другой работы event loop.
- then, catch, finally и продолжение после await планируются как microtasks.
- Microtasks не являются отдельной фазой event loop libuv.
- Длинная цепочка microtasks может задержать таймеры и I/O callbacks, хотя каждый шаг асинхронный.
Зачем это спрашивают: Сильный ответ размещает Promise callbacks между JavaScript-задачами и не называет их фазой event loop.
Блокировка event loop не позволяет процессу выполнять другие JavaScript callbacks во время этой работы.
- CPU-heavy циклы и синхронный I/O увеличивают задержку несвязанных запросов в том же процессе.
- Неблокирующие API позволяют event loop обслуживать другую работу во время ожидания I/O.
- Крупные CPU-задачи лучше переносить в worker threads, child processes или другой сервис.
Зачем это спрашивают: Интервьюер проверяет, связываете ли вы синхронную работу основного потока с задержкой всего сервиса.
Пул потоков libuv выполняет отдельные блокирующие или CPU-intensive нативные операции вне потока event loop.
- Частые примеры включают многие fs API, dns.lookup, crypto-операции и zlib.
- Завершение передаётся обратно, чтобы соответствующий callback или Promise продолжился в потоке event loop.
- I/O сетевых sockets обычно использует готовность операционной системы, а не отдельный поток pool на соединение.
Зачем это спрашивают: Сильный ответ называет характерную работу thread pool и не утверждает, что все асинхронные операции используют потоки.
Callback это функция, переданная другой операции для вызова после завершения работы или наступления события.
- Запускающая функция может вернуться до выполнения асинхронного callback.
- Callback получает результат, ошибку или аргументы события согласно контракту API.
- Callbacks применяются и для синхронной итерации, поэтому асинхронность определяется контрактом API.
Зачем это спрашивают: Интервьюер проверяет, определяете ли вы callback через управление потоком без предположения, что любой callback асинхронный.
Error-first callback получает ошибку первым аргументом, а данные успеха последующими аргументами.
- null или отсутствие первого аргумента означает успех операции.
- Если первый аргумент не равен null или undefined, ошибку обычно нужно обработать или передать дальше.
- Многие старые Node.js API используют форму callback(error, result), которую можно адаптировать к Promise через promisify.
Зачем это спрашивают: Сильный ответ знает порядок аргументов и необходимое ветвление.
Callback hell это глубоко вложенный асинхронный поток управления, в котором трудно отслеживать порядок, ошибки и очистку.
- Именованные функции и ранние возвраты делают callback-код более плоским.
- Promise выражают последовательности через возвращаемые цепочки и общую обработку catch.
- async и await дают синтаксис, похожий на последовательный, сохраняя асинхронность Promise.
Зачем это спрашивают: Интервьюер проверяет понимание проблемы поддерживаемости, а не только узнавание вложенных отступов.
Promise находится в состоянии ожидания pending, пока не завершится успешно fulfilled или с отклонением rejected.
- Fulfilled и rejected являются двумя завершёнными settled-состояниями.
- После завершения Promise не может изменить состояние или результат.
- Обработчики можно добавить до или после завершения, и они всё равно выполнятся асинхронно как microtasks.
Зачем это спрашивают: Интервьюер оценивает, знаете ли вы жизненный цикл Promise и асинхронное поведение обработчиков.
then обрабатывает fulfillment, catch обрабатывает rejection, а finally запускает код очистки после любого исхода.
- Каждый метод возвращает новый Promise, позволяя продолжить композицию.
- Возвращённое обработчиком значение переводит следующий Promise в fulfilled, а выброшенная ошибка отклоняет его.
- finally обычно сохраняет предыдущее значение или ошибку, если его callback не выбросит ошибку и не вернёт rejected Promise.
Зачем это спрашивают: Сильный ответ объясняет семантику цепочки, а не описывает методы как простые callbacks.
Возврат из обработчика then связывает его результат со следующим Promise в цепочке.
- Возврат обычного значения выполняет следующий шаг успешно с этим значением.
- Возврат Promise заставляет цепочку дождаться и принять его исход.
- Забытый return может продолжить внешнюю цепочку с undefined раньше завершения вложенной работы.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы сохранение порядка и ошибок через композицию Promise.
Promise.all выполняется успешно после успеха всех входов и отклоняется при первом отклонении одного из них, а Promise.allSettled сообщает каждый исход.
- Promise.all сохраняет порядок входов в массиве успешных результатов.
- Его раннее отклонение не отменяет автоматически остальные запущенные операции.
- allSettled возвращает объекты status для fulfilled и rejected входов, что полезно, когда важен каждый результат.
Зачем это спрашивают: Сильный ответ различает сбор результатов, поведение ошибок и отсутствие автоматической отмены.
Async-функция всегда возвращает Promise своего будущего результата.
- Возврат обычного значения успешно выполняет этот Promise со значением.
- Выброшенная внутри функции ошибка отклоняет возвращаемый Promise.
- Тело функции может использовать await для приостановки собственного продолжения без блокировки потока event loop.
Зачем это спрашивают: Интервьюер проверяет, связываете ли вы async-функции с возвратом Promise и семантикой отклонения.
Закрытые вопросы
- 21
Что делает await?
async - 22
Как обрабатываются ошибки с async и await?
async - 23
Что такое необработанное отклонение Promise?
promises - 24
Как CommonJS объявляет и загружает модули?
modules - 25
Как ECMAScript modules объявляют и загружают модули в Node.js?
- 26
Каковы основные различия CommonJS и ESM в Node.js?
modules - 27
Как Node.js определяет, является ли файл .js модулем CommonJS или ESM?
modules - 28
Как работает кеширование модулей в Node.js?
cachingmodules - 29
Чем __dirname и __filename отличаются в CommonJS и ESM?
modules - 30
Для чего используется package.json?
npm - 31
Чем отличаются dependencies, devDependencies и peerDependencies?
dependencies - 32
Что такое npm scripts?
npm - 33
Что означает semantic versioning в диапазоне npm-зависимости?
dependenciesnpmversioning - 34
Почему lockfile пакетов важен?
packaging - 35
Для чего используется npx?
- 36
Что предоставляет встроенный модуль fs?
- 37
Для чего используются path.join и path.resolve?
joins - 38
Как встроенный модуль http представляет HTTP-запрос и ответ сервера?
http - 39
Что такое EventEmitter?
- 40
Чем отличаются on, once и removeListener у EventEmitter?
- 41
Каковы основные виды streams в Node.js?
- 42
Как readable stream может передавать данные?
- 43
Что такое backpressure в streams Node.js?
backpressure - 44
Чем отличаются writable.write и writable.end?
- 45
Что такое Buffer в Node.js?
- 46
Как текстовые кодировки влияют на преобразование Buffer?
- 47
Что такое process.env?
concurrency - 48
Какие полезные данные и средства управления предоставляет объект process?
concurrency - 49
Что такое middleware в Express?
middleware - 50
Чем middleware-функция обработки ошибок Express отличается от обычной?
middleware - 51
Вы реализуете POST /tasks в Express. Как вы проверите запрос и вернёте корректный ответ о создании?
validation - 52
GET /users/:id сейчас возвращает 200 с null, если пользователь не найден. Как вы исправите обработчик?
fundamentals - 53
Как вы безопасно разберёте page и limit для GET /products?page=2&limit=20?
- 54
Эндпоинт PATCH /users/:id передаёт req.body в обновление базы через spread. Как сделать его безопасным?
databaseendpointsspread - 55
Эндпоинт Express принимает очень большие JSON-тела, а некорректный JSON превращается в общий ответ 500. Как это исправить?
endpointsgenerics - 56
Защищённый маршрут Express получает undefined в req.body, а проверка аутентификации не запускается. В каком порядке вы подключите middleware?
authmiddlewarefundamentals - 57
Как вы реализуете guard аутентификации, который добавляет req.user для защищённого эндпоинта Express?
authendpoints - 58
Несколько эндпоинтов возвращают разные JSON-структуры для похожих успешных ответов и ошибок. Как вы приведёте их к единому виду?
endpoints - 59
Эндпоинт загрузки файлов принимает файлы любого количества и размера и иногда исчерпывает память. Как вы это исправите?
memoryendpoints - 60
Вам нужно добавить валидацию нового эндпоинта, а в проекте может использоваться Fastify или Express. Как вы выберете подход?
validationendpoints - 61
Маршрут сначала ждёт getUser(id), а затем getOrders(id), хотя вызовы не зависят друг от друга. Как сократить время ответа?
async - 62
Promise.all отклоняется, пока маршрут загружает несколько обязательных записей. Как маршруту обработать эту ошибку?
promises - 63
Дашборд может работать, даже если один из пяти необязательных источников данных недоступен. Как собрать успешные данные и отдельно учесть ошибки?
- 64
Код запускает createOrder() и chargePayment(order.id) через Promise.all, но для оплаты нужен ID нового заказа. Как исправить этот поток?
promises - 65
Нужно обработать 100 000 файлов конкурентно, но одновременный запуск 100 000 Promises перегрузит память и файловую систему. Как ограничить конкурентность?
promisesconcurrencymemory - 66
Сервис использует callback-версию fs.readFile и ещё одно старое API с error-first callback. Как сделать оба вызова удобными для async и await?
asynccallbacksapi - 67
Условие if (isAllowed(user)) всегда срабатывает, потому что isAllowed является async-функцией. В чём ошибка и как её исправить?
async - 68
Функция saveUser вызывает database.save(user) внутри фигурных скобок, но сразу возвращает undefined. Как исправить её, чтобы вызывающий код мог дождаться сохранения и получить ошибку?
asyncfundamentalsdatabase - 69
Запрос к внешнему API иногда завершается ошибкой. Как добавить повторы, не дублируя записи и не повторяя постоянные ошибки?
resilienceapi - 70
Как остановить fetch-запрос через три секунды и одновременно позволить вызывающему коду отменить его через AbortController?
- 71
Небольшой файл настроек содержит JSON. Как загрузить его, не скрывая ошибки синтаксиса JSON?
- 72
Маршрут использует readFile для отправки архива размером в несколько гигабайт. Что вы измените?
- 73
Сжатие файла использует source.pipe(gzip).pipe(destination), но иногда зависает или пропускает ошибку. Как это исправить?
- 74
Как скачать большой HTTP-ответ на диск, не накапливая всё тело в памяти?
http - 75
Нужно обрабатывать большой CSV-экспорт по одной записи. Будете ли вы разделять входящие chunks по символу новой строки?
concurrency - 76
Небольшое приложение иногда оставляет наполовину записанный JSON-файл состояния после сбоя. Как сделать запись достаточно атомарной?
concurrency - 77
Endpoint получает имя файла и отдаёт файл из директории uploads. Как защититься от path traversal?
endpoints - 78
Экспорт отчёта вызывает writable.write(chunk) в быстром цикле, и потребление памяти постоянно растёт. Как учесть backpressure?
backpressurememory - 79
Кириллица повреждается при чтении из stream, а бинарные вложения должны оставаться неизменными. Как выбрать между строками и Buffer?
- 80
Endpoint чтения файла должен возвращать not found для отсутствующего файла, но сейчас превращает любую ошибку в 404. Как это исправить?
endpoints - 81
Вызов через встроенный fetch в Node.js попадает в успешную ветку, когда внешнее API возвращает 500. Как исправить этот поток?
api - 82
Внешнее API вернуло статус 200 и валидный JSON, но в нём нет обязательного id пользователя. Что должен сделать Node.js-сервис?
api - 83
Код логирует await response.text(), а затем вызывает response.json(), который падает с ошибкой уже использованного body. Как это исправить?
async - 84
Как безопасно построить URL с query-параметрами и добавить аутентификацию для запроса к внешнему API?
queriesapiauth - 85
Существующий Node.js-проект уже использует Axios через общий API-клиент, но теперь доступен встроенный fetch. Что вы выберете для новой внешней интеграции?
api - 86
Внешнее API возвращает 401 из-за истёкшего access token. Как обновить токен и не создать бесконечный цикл повторов?
tokensapiresilience - 87
Как получить все результаты из внешнего API с cursor pagination?
pagination - 88
Почему сервис должен преобразовывать ошибки внешнего API, а не передавать вызывающему коду ошибку fetch или Axios напрямую?
api - 89
Как ошибки из асинхронного маршрута Express или Fastify должны попадать в централизованный обработчик?
async - 90
Как не допустить утечки внутренних деталей при ошибке внешнего API через ваш Node.js-эндпоинт?
endpoints - 91
Команда Node.js сообщает о необработанном отклонении Promise и завершается; как найти и исправить причину, не скрывая ошибку глобально?
- 92
Вам достались вложенные callbacks, которые читают файл, разбирают его и сохраняют запись; как вы отрефакторите этот поток?
refactoringownershipcallbacks - 93
Маршрут Express иногда выбрасывает ошибку 'Cannot set headers after they are sent'; как вы найдёте и исправите проблему?
- 94
Один запрос к приложению Express навсегда остаётся в ожидании без ответа; что вы проверите?
- 95
Эндпоинт запускает большой вычислительный цикл, после чего все остальные запросы замедляются; как вы решите проблему?
endpoints - 96
Почему async forEach завершает внешнюю функцию до окончания обновлений базы данных и как это исправить?
databaseasync - 97
Продакшн-запрос периодически завершается ошибкой; какой контекст вы залогируете для отладки без раскрытия секретов?
secrets - 98
Как протестировать POST-эндпоинт Express или Fastify, не запуская сервер на реальном порту?
endpoints - 99
Приложение запускается с некорректным PORT, а позже падает из-за отсутствующего URL базы данных; как улучшить работу с конфигурацией?
databaseconfig - 100
Как добавить graceful shutdown в HTTP-сервис Node.js, у которого также есть пул соединений с базой данных?
databasehttplifecycle