Как найти, какие обещания не обрабатываются в Node.js Необработанное предупреждение об отказе от обещания?

#node.js

#node.js #обещание #асинхронное ожидание #предупреждения #необработанное-исключение

Вопрос:

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

 (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.
  

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

Комментарии:

1. Вы могли бы использовать библиотеку Bluebird promise, и это, вероятно, дало бы вам трассировку стека.

2. Возможно, регистрация на unhandledRejection событие узла поможет? Смотрите Документы . Ваш обратный вызов получает Error объект и фактическое Promise значение, и я полагаю Error , что объект может содержать трассировку стека.

3. Если два предыдущих комментария не помогают, то Can't set headers after they are sent. должны дать вам подсказку, где в вашем коде это может произойти (т. Е. Где-то вы устанавливаете заголовки после того, как заголовки были бы уже отправлены — предположительно, из-за сбоя в понимании асинхронного кода, но это предположение)

4. привет, что сообщения помогают точно определить, где в коде ошибка, кстати, это не так просто, как знать строку.

5. @jfriend00 Оказывается, это была ситуация, когда асинхронная функция выдавала ошибку — эти внутренние обещания узла для асинхронных функций никогда не используют Bluebird, поэтому наличие Bluebird не помогает в этом сценарии.

Ответ №1:

прослушивание 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
});
  

Комментарии:

1. Ведение error.stack журнала (или в приведенном выше примере reason.stack ) дает вам полную трассировку стека ошибки.

2. Хотел бы я сказать, что это сработало, но это не так. Я на узле 8.9.4.

3. Я попробовал приведенный выше код и получил неопределенный как для reason, так и для p? Есть предложения? » Необработанное отклонение при: Обещание { состояние: ‘отклонено’, причина: не определено } причина: не определено »

4. Я добавил этот код в начало моего app.js файла узла, и, к сожалению, ничего не зарегистрировано. Узел v10.13.0 .

5. Почему, черт возьми, это не часть поведения узла по умолчанию? Я нахожусь на версии 14.8.0, и он по-прежнему показывает совершенно бесполезные сообщения, даже когда я использую. --trace-warnings

Ответ №2:

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

узел --трассировка-предупреждения app.js

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

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

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

Комментарии:

1. Используя узел 7.8.0, и все это дает мне трассировку стека для множества внутренних модулей узла. (узел: 10372) UnhandledPromiseRejectionWarning: отклонение необработанного обещания (идентификатор отклонения: 2): не определено при emitWarning (internal/process/promises.js:59:21) при отправке необработанных отказов (internal/process /promises.js:86:11) в процессе. _tickDomainCallback (internal/process/next_tick.js:136:7)

2. Я не вижу никакого вывода, который показывает, где проблема с необработанным обещанием.

3. Я добавил это в package.json start script, и, к сожалению, ничего не было зарегистрировано. Узел v10.13.0 .

4. @user1063287 Убедитесь, что флаг находится в правильном месте в вашей команде. Я только что добавил обновление к ответу, чтобы подчеркнуть, что оно должно идти перед именем скрипта.

5. Вероятно, вы смотрите на трассировку стека предупреждения об устаревании, а не на исходную необработанную ошибку (которая должна быть где-то выше предупреждения об устаревании).

Ответ №3:

Ведение журнала с помощью трассировки стека

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

 process.on('unhandledRejection', (error, p) => {
  console.log('=== UNHANDLED REJECTION ===');
  console.dir(error.stack);
});
  

Комментарии:

1. Единственное функциональное отличие заключается в создании console.dir в свойстве стека ошибки. Значительная разница в выводе по сравнению с принятым ответом.

2. Я пробовал это, но error.stack undefined для меня. 🙁 узел v14.15.4

3. Это будет работать только тогда, когда ошибка является экземпляром ошибки. Это не сработает, если обещание будет отклонено, например, со строковым значением: throw "Some error"

4. будет ли это работать, если не произойдет сбой? 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. Сейчас это не сбой, и я хочу исправить это, прежде чем у него появится шанс в будущем.

Ответ №4:

Этот модуль позволил мне отследить обещание (ы) виновника: https://www.npmjs.com/package/trace-unhandled

  1. Установить

     npm i trace-unhandled
      
  2. Включить в код

     require('trace-unhandled/register');
      

Комментарии:

1. Красиво, подключи и играй!

2. Узел 14.19.1: не помогло, все еще получаю at emitUnhandledRejectionWarning (internal/process/promises.js:170:15) (и это самое близкое, что я получаю к фактической строке)

3. Спасибо за этот очень простой ответ. Через несколько часов найдено недостающее ожидание через 2 минуты после нахождения этого сообщения.

Ответ №5:

@Jeremy У меня был тот же результат, reason переменная, предоставленная

 process.on('unhandledRejection', (reason, p) => {});
  

не был определен, и мне требуется время, чтобы выяснить, что в моем коде были отклонения от обещаний, которые обычно ничего не дают:

 new Promise((resolve reject) => {
  const client = net.connect(options)
  client.on("connect", () => {
    resolve()
  })
  client.on("error", () => {
    reject()
  })
})
  

проблема в том, что у вас reject ничего нет, чтобы получить трассировку, вы должны указать ошибку, например

 new Promise((resolve reject) => {
  const client = net.connect(options)
  client.on("connect", () => {
    resolve()
  })
  client.on("error", (err) => {
    reject(err)
  })
})
  

и если у вас нет ошибки, вы можете предоставить ее самостоятельно, даже если она пуста, это даст трассировку стека

 reject(new Error())
  

Если вам нужно найти, откуда была вызвана ошибка, найдите в своем коде Promise с пустым отклонением

Комментарии:

1. да, у меня буквально сотни асинхронных функций, и нет более быстрого способа найти его, чем попытаться отследить каждое отдельное место, где создается обещание, явно или неявно?