#Что означает ошибка и когда она возникает
Node.js продолжает работу, пока есть активные ресурсы цикла событий: например, setInterval, сервер, некоторые сокеты или ожидающие операции. Если программа напечатала финальную строку, но терминал не вернул приглашение, сначала определите удерживающий ресурс. Это не обязательно утечка памяти и не повод завершать все процессы Node.js.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Забыли clearIntervalПовторяющийся таймер setInterval остаётся активным после завершения основной работы. | В коде есть setInterval, но нет парного clearInterval при остановке. | Хранить идентификатор таймера и очищать его в процедуре завершения. |
| Сервер продолжает принимать соединенияhttp.createServer().listen() удерживает процесс, пока сервер не закрыт. | Порт остаётся в LISTEN, завершение задачи не вызывает server.close(). | Останавливать приём новых соединений, корректно завершать активные. |
| Открытый клиентский сокет или соединение с БДСетевая библиотека имеет собственный пул соединений или открытое соединение. | Приложение прошло всю работу, но после закрытия БД/сокета завершается. | Использовать штатный метод закрытия клиента/pool при завершении задачи. |
#Пошаговая диагностика и устранение
- Проверьте, действительно ли программа завислаЗапустите свою команду в терминале редактора VS Code (Терминал → Создать терминал), например
node task.cjs. Если последняя ожидаемая строка уже напечатана, а приглашение не вернулось, зафиксируйте время и убедитесь, что программа не является постоянно работающим сервером по замыслу. - Отделите фоновую службу от одноразового скриптаОткройте package.json и посмотрите scripts.start. Если запускается HTTP-сервер или бот, его постоянная работа нормальна: не заставляйте его завершаться после ответа. Если это экспорт, проверка или разовая задача, перейдите к поиску таймеров и соединений.
- Найдите периодические таймеры и интервалыВ VS Code нажмите Ctrl+Shift+F и найдите
setInterval(, затемsetTimeout(. Для каждого setInterval проверьте, где сохраняется возвращаемый объект и кто вызывает clearInterval. В учебной программе интервал без очистки удерживает процесс бесконечно; ниже приведён полностью управляемый вариант. - Убедитесь, что сервер закрывают штатноНайдите
.listen(и сохранённую ссылку на http.Server. Для одноразового тестового сервера вызовитеserver.close(callback): он перестаёт принимать новые подключения и вызовет callback после завершения существующих. На боевом HTTP-сервере планируйте остановку с учётом запросов и балансировщика; не вызывайте process.exit() в середине отправки ответа. - Осмотрите соединения к базе и внешним службамПоиск по проекту:
createConnection,connect,createPool,createServer,new WebSocket. Для конкретной библиотеки найдите в её официальной документацииclose(),end()илиdestroy()и используйте только соответствующий API. Не закрывайте соединение, пока выполняется запрос или отправляются данные. - Воспроизведите и исправьте случай с таймеромВ отдельной пустой папке сохраните hang.cjs и запустите
node hang.cjs: терминал останется занят. Для исправления используйте managed.cjs из примера ниже; через короткое время появитсяОстановленои терминал вернётся. Оба файла — учебные, они не меняют приложение. - Добавьте контролируемое завершение приложенияПри завершении задачи сначала прекратите порождать новые операции, затем очистите интервалы, закройте клиентские соединения и вызовите server.close, если есть сервер. Для необязательного служебного таймера можно рассмотреть
timer.unref(): это позволяет завершиться процессу, но отложенная задача может не выполниться, поэтому не делайте так с критической работой. - Проверьте в реальной команде запуска и при необходимости откатитеПерезапустите конкретный процесс после сохранения правок. В одноразовой задаче ожидается возврат приглашения терминала и код выхода 0; у сервера — корректное завершение после предусмотренного сигнала. Если сокеты остаются открытыми, добавьте временные журналы жизненного цикла ресурсов без секретов. При потере запросов верните предыдущее поведение по Git и исправьте порядок shutdown.
- Файлы сохранить по примерам нижеLinux · Терминал (Bash)КомандаФайлы сохранить по примерам ниже. hang.cjs намеренно остаётся запущенным; для остановки нажмите Ctrl+C в том же терминале. managed.cjs завершится самостоятельно.
node --versionnode hang.cjsnode managed.cjs
#Минимальный пример и проверка на тестовом проекте
setInterval(() => { console.log("Таймер ещё активен"); }, 1000);const timer = setInterval(() => console.log("Работаю"), 100);
setTimeout(() => {
clearInterval(timer);
console.log("Остановлено");
}, 350);#Проверка результата и действия при неуспехе
Разовая задача завершается сама, а все ожидаемые записи выполнены. Если остались слушающие сокеты, проверьте пул соединений и сервер отдельно; если приложение серверное — постоянный процесс сам по себе не ошибка. Запишите версию Node.js и собственные логи создания/закрытия ресурсов.