Как найти, какие обещания не обрабатываются в Node.js UnhandledPromiseRejectionWarning?

177

Node.js из версии 7 имеет асинхронный / ожидающий синтаксический сахар для обработки обещаний, и теперь в моем коде довольно часто появляется следующее предупреждение:

(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise 
rejection (rejection id: 1): ReferenceError: Error: Can't set headers 
after they are sent.
(node:11057) DeprecationWarning: Unhandled promise rejections are 
deprecated. In the future, promise rejections that are not handled 
will terminate the Node.js process with a non-zero exit code.

К сожалению, нет ссылки на линию, где отсутствует улов. Есть ли способ найти его, не проверяя каждый блок try / catch?

user1658162
источник
Вы можете использовать библиотеку обещаний Bluebird, и она, вероятно, даст вам трассировку стека.
jfriend00
3
Возможно, регистрация на unhandledRejectionсобытие Node поможет? Смотрите документы . Ваш обратный вызов получает Errorобъект и фактическое Promise, и я считаю, что Errorобъект может содержать трассировку стека.
YSK
Если два предыдущих комментария не помогли, тогда Can't set headers after they are sent.вы должны дать подсказку, где в вашем коде это может происходить (т.е. где вы устанавливаете заголовки после того, как заголовки уже были отправлены - возможно, из-за сбоя в понимании асинхронного кода , но это предположение)
Jaromanda X
Привет, что сообщения помогают точно определить, где в коде ошибка, кстати, это не так просто, как знать строку.
user1658162
1
@ jfriend00 Оказывается, это была ситуация, когда асинхронная функция выдавала ошибку - эти внутренние обещания Node для асинхронных функций никогда не используют Bluebird, поэтому наличие Bluebird в этом сценарии не помогает.
Адам Рейс

Ответы:

298

прослушать unhandledRejectionсобытие процесса.

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});
cuixiping
источник
35
Ведение журнала error.stack(или в приведенном выше примере reason.stack) дает полную трассировку стека ошибки.
Адам Рейс
9
Я хотел бы сказать, что это сработало, но это не так. Я на Узле 8.9.4.
ffxsam
2
Я попробовал приведенный выше код и получил неопределенный по причине, и р? Какие-либо предложения? «Необработанный отказ в: Обещании {состояние:« отклонено », причина: не определена} причина: не определена»
Джереми,
1
Попробовал это, и это сработало как шарм! Решил мою проблему очень быстро.
кому - л
3
Я добавил этот код в начало моего app.jsфайла узлов, и, к сожалению, ничего не регистрируется. Узел v10.13.0.
user1063287
71

Правильный путь , чтобы показать полную трассировку стеки для необработанных отбраковок ES6 Promise, является запуск Node.js с --trace-warningsфлагом. Это покажет полную трассировку стека для каждого предупреждения, без необходимости перехватывать отклонение из вашего собственного кода. Например:

узел --trace-warnings app.js

Убедитесь, что trace-warningsфлаг стоит перед именем вашего .jsфайла! В противном случае флаг будет интерпретирован как аргумент вашего скрипта и будет игнорироваться самим Node.js.

Если вы действительно хотите обрабатывать необработанные отклонения (например, регистрируя их), то вы можете unhandled-rejectionвместо этого использовать мой модуль, который перехватывает все необработанные отклонения для каждой крупной реализации Promises, которая его поддерживает, с помощью одного обработчика событий.

Этот модуль поддерживает Bluebird, ES6 Promises, Q, WhenJS, es6-promise, then/promiseи что - нибудь , который соответствует любому из необработанной спецификации отбраковки (полные детали в документации).

Свен Слотвег
источник
20
Использование узла 7.8.0 и все это дает мне трассировку стека для группы внутренних узлов. (узел: 10372) UnhandledPromiseRejectionWarning: необработанное отклонение обещания (id отклонения: 2): не определено в emitWarning (внутреннее / process / promises.js: 59: 21) в emitPendingUnhandledRejected (внутреннее / process / promises.js: 86: 11) в процессе ._tickDomainCallback (internal / process / next_tick.js: 136: 7)
Уилл Ловетт,
3
Я не вижу выводов, показывающих, где проблема необработанного обещания.
Джейсон Лич
Я добавил это, чтобы package.jsonзапустить скрипт, и к сожалению ничего не было зарегистрировано. Узел v10.13.0.
user1063287
1
@ user1063287 Убедитесь, что флаг находится в правильном месте в вашей команде. Я только добавил обновление к ответу, чтобы подчеркнуть, что оно должно идти перед именем скрипта.
Свен Слотвег,
2
Скорее всего, вы просматриваете трассировку стека предупреждения об устаревании, а не исходную необработанную ошибку (которая должна быть где-то выше предупреждения об устаревании).
Свен Слотвег
7

Ведение журнала с трассировкой стека

Если вы ищете более полезное сообщение об ошибке. Попробуйте добавить это в ваш файл узла. Он должен отображать полную трассировку стека, где происходит ваш сбой.

process.on('unhandledRejection', (error, p) => {
  console.log('=== UNHANDLED REJECTION ===');
  console.dir(error.stack);
});
joshuakcockrell
источник
Единственным функциональным отличием является создание console.dir для свойства стека ошибки. Разница в результатах по сравнению с принятым ответом.
joshuakcockrell