Node.js WindowsLinuxmacOS

Почему процесс Node.js остаётся запущенным после выполнения программы

  • Обновлено
  • Чтение ≈ 4 минуты

Краткий ответ

Node.js продолжает работу, пока есть активные ресурсы цикла событий: например, setInterval, сервер, некоторые сокеты или ожидающие операции. Если программа напечатала финальную строку, но терминал не вернул приглашение, сначала определите удерживающий ресурс. Это не обязательно утечка памяти и не повод завершать все процессы Node.js.

В этой статье
  1. Что означает ошибка и когда она возникает
  2. Как отличить возможные причины
  3. Пошаговая диагностика и устранение
  4. Минимальный пример и проверка на тестовом проекте
  5. Проверка результата и действия при неуспехе

#Что означает ошибка и когда она возникает

Node.js продолжает работу, пока есть активные ресурсы цикла событий: например, setInterval, сервер, некоторые сокеты или ожидающие операции. Если программа напечатала финальную строку, но терминал не вернул приглашение, сначала определите удерживающий ресурс. Это не обязательно утечка памяти и не повод завершать все процессы Node.js.

#Как отличить возможные причины

Возможная причинаКак узнатьЧто делать
Забыли clearIntervalПовторяющийся таймер setInterval остаётся активным после завершения основной работы.В коде есть setInterval, но нет парного clearInterval при остановке.Хранить идентификатор таймера и очищать его в процедуре завершения.
Сервер продолжает принимать соединенияhttp.createServer().listen() удерживает процесс, пока сервер не закрыт.Порт остаётся в LISTEN, завершение задачи не вызывает server.close().Останавливать приём новых соединений, корректно завершать активные.
Открытый клиентский сокет или соединение с БДСетевая библиотека имеет собственный пул соединений или открытое соединение.Приложение прошло всю работу, но после закрытия БД/сокета завершается.Использовать штатный метод закрытия клиента/pool при завершении задачи.

#Пошаговая диагностика и устранение

  1. Проверьте, действительно ли программа завислаЗапустите свою команду в терминале редактора VS Code (Терминал → Создать терминал), например node task.cjs. Если последняя ожидаемая строка уже напечатана, а приглашение не вернулось, зафиксируйте время и убедитесь, что программа не является постоянно работающим сервером по замыслу.
  2. Отделите фоновую службу от одноразового скриптаОткройте package.json и посмотрите scripts.start. Если запускается HTTP-сервер или бот, его постоянная работа нормальна: не заставляйте его завершаться после ответа. Если это экспорт, проверка или разовая задача, перейдите к поиску таймеров и соединений.
  3. Найдите периодические таймеры и интервалыВ VS Code нажмите Ctrl+Shift+F и найдите setInterval(, затем setTimeout(. Для каждого setInterval проверьте, где сохраняется возвращаемый объект и кто вызывает clearInterval. В учебной программе интервал без очистки удерживает процесс бесконечно; ниже приведён полностью управляемый вариант.
  4. Убедитесь, что сервер закрывают штатноНайдите .listen( и сохранённую ссылку на http.Server. Для одноразового тестового сервера вызовите server.close(callback): он перестаёт принимать новые подключения и вызовет callback после завершения существующих. На боевом HTTP-сервере планируйте остановку с учётом запросов и балансировщика; не вызывайте process.exit() в середине отправки ответа.
  5. Осмотрите соединения к базе и внешним службамПоиск по проекту: createConnection, connect, createPool, createServer, new WebSocket. Для конкретной библиотеки найдите в её официальной документации close(), end() или destroy() и используйте только соответствующий API. Не закрывайте соединение, пока выполняется запрос или отправляются данные.
  6. Воспроизведите и исправьте случай с таймеромВ отдельной пустой папке сохраните hang.cjs и запустите node hang.cjs: терминал останется занят. Для исправления используйте managed.cjs из примера ниже; через короткое время появится Остановлено и терминал вернётся. Оба файла — учебные, они не меняют приложение.
  7. Добавьте контролируемое завершение приложенияПри завершении задачи сначала прекратите порождать новые операции, затем очистите интервалы, закройте клиентские соединения и вызовите server.close, если есть сервер. Для необязательного служебного таймера можно рассмотреть timer.unref(): это позволяет завершиться процессу, но отложенная задача может не выполниться, поэтому не делайте так с критической работой.
  8. Проверьте в реальной команде запуска и при необходимости откатитеПерезапустите конкретный процесс после сохранения правок. В одноразовой задаче ожидается возврат приглашения терминала и код выхода 0; у сервера — корректное завершение после предусмотренного сигнала. Если сокеты остаются открытыми, добавьте временные журналы жизненного цикла ресурсов без секретов. При потере запросов верните предыдущее поведение по Git и исправьте порядок shutdown.
  9. Файлы сохранить по примерам ниже
    Linux · Терминал (Bash)Команда
    Файлы сохранить по примерам ниже. hang.cjs намеренно остаётся запущенным; для остановки нажмите Ctrl+C в том же терминале. managed.cjs завершится самостоятельно.
    node --version
    node hang.cjs
    node managed.cjs

#Минимальный пример и проверка на тестовом проекте

Текст
Учебный hang.cjs: программа повторяет сообщение и не завершается, пока её не остановить Ctrl+C.
setInterval(() => { console.log("Таймер ещё активен"); }, 1000);
Текст
Учебный managed.cjs: очистка интервала приводит к нормальному завершению. На реальном сервере аналогично нужны закрытие подключений и ожидание завершения операций.
const timer = setInterval(() => console.log("Работаю"), 100);
setTimeout(() => {
  clearInterval(timer);
  console.log("Остановлено");
}, 350);

#Проверка результата и действия при неуспехе

Разовая задача завершается сама, а все ожидаемые записи выполнены. Если остались слушающие сокеты, проверьте пул соединений и сервер отдельно; если приложение серверное — постоянный процесс сам по себе не ошибка. Запишите версию Node.js и собственные логи создания/закрытия ресурсов.

Источники и обновления

Последнее обновление статьи: 2 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.