¿Cómo encontrar qué promesas no se manejan en Node.js UnhandledPromiseRejectionWarning?

177

Node.js de la versión 7 tiene azúcar sintáctico asíncrono / en espera para manejar las promesas y ahora en mi código aparece la siguiente advertencia con bastante frecuencia:

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

Desafortunadamente, no hay referencia a la línea donde falta la captura. ¿Hay alguna forma de encontrarlo sin verificar cada bloque try / catch?

usuario1658162
fuente
Podrías usar la biblioteca de promesa de Bluebird y es probable que te dé un seguimiento de la pila.
jfriend00
3
¿Quizás unhandledRejectionte ayude registrarte en el evento de Node ? Ver los documentos . Su devolución de llamada obtiene el Errorobjeto y el real Promise, y creo que el Errorobjeto podría contener un seguimiento de la pila.
YSK
Si los dos comentarios anteriores no ayudan, entonces Can't set headers after they are sent.debería darle una pista de dónde podría estar sucediendo en su código (es decir, en algún lugar en el que está configurando encabezados después de que los encabezados ya se hayan enviado, presumiblemente debido a una falla en la comprensión del código asincrónico , pero eso es una suposición)
Jaromanda X
Hola, los mensajes ayudan a encontrar con seguridad en qué parte del código se encuentra el error, por cierto, no es tan fácil como conocer la línea.
user1658162
1
@ jfriend00 Resulta que era una situación en la que una función asincrónica arrojaba un error: esas promesas internas de Nodo para funciones asincrónicas no usan Bluebird, por lo que tener Bluebird no ayuda en ese escenario.
Adam Reis

Respuestas:

297

escuchar unhandledRejectionevento de proceso.

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
fuente
35
El registro error.stack(o en el ejemplo anterior reason.stack) le proporciona el seguimiento completo de la pila del error.
Adam Reis
Gracias por poner en process.onlugar de server.ongustar en tantos otros ejemplos que he encontrado
PhillipHolmes
9
Desearía poder decir que esto funcionó, pero no funciona. Estoy en el Nodo 8.9.4.
ffxsam
2
Intenté el código anterior y obtuve indefinición por ambas razones, y p? ¿Alguna sugerencia? "Rechazo no controlado en: Promesa {estado: 'rechazado', motivo: indefinido} motivo: indefinido"
Jeremy
3
Agregué este código a la parte superior de mi app.jsarchivo de nodo y desafortunadamente no se registra nada. Nodo v10.13.0.
user1063287
71

La forma correcta de mostrar un seguimiento completo de la pila para los rechazos no prometidos de ES6 Promise es ejecutar Node.js con el --trace-warningsindicador. Esto mostrará el seguimiento completo de la pila para cada advertencia, sin tener que interceptar el rechazo desde su propio código. Por ejemplo:

nodo --trace-warnings app.js

¡Asegúrese de que la trace-warningsbandera aparezca antes del nombre de su .jsarchivo! De lo contrario, el indicador se interpretará como un argumento para su secuencia de comandos, y el propio Node.js lo ignorará.

Si realmente desea manejar los rechazos no controlados (por ejemplo, registrándolos), es posible que desee utilizar mi unhandled-rejectionmódulo en su lugar, que captura todos los rechazos no controlados para cada implementación importante de Promises que lo admita, con un solo controlador de eventos.

Que soporta los módulos Bluebird, promesas ES6, Q, WhenJS, es6-promise, then/promise, y cualquier cosa que se ajusta a ninguna de las especificaciones de rechazo no controladas (detalles en la documentación).

Sven Slootweg
fuente
20
Usando el nodo 7.8.0 y todo esto me da un seguimiento de la pila para un montón de módulos de nodo interno. (nodo: 10372) UnhandledPromiseRejectionWarning: Rechazo de promesa no controlado (id. de rechazo: 2): indefinido en emitWarning (interno / proceso / promesas.js: 59: 21) en emitPendingUnhandledRejections (interno / proceso / promesas.js: 86: 11) en proceso ._tickDomainCallback (internal / process / next_tick.js: 136: 7)
Will Lovett el
3
No veo ningún resultado que muestre dónde está el problema de la promesa no controlada.
Jason Leach
Agregué esto para package.jsoniniciar el script y desafortunadamente no se registró nada. Nodo v10.13.0.
user1063287
1
@ user1063287 Asegúrese de que la bandera esté en el lugar correcto en su comando. Acabo de agregar una actualización a la respuesta, para enfatizar que debe ir antes del nombre del script.
Sven Slootweg
2
Es probable que esté viendo el seguimiento de la pila de la advertencia de desaprobación, no del error original no manejado (que debería estar en algún lugar por encima de la advertencia de desaprobación).
Sven Slootweg
7

Registro con seguimiento de pila

Si está buscando más de un mensaje de error útil. Intente agregar esto a su archivo de nodo. Debería mostrar el seguimiento de la pila completa donde está ocurriendo su bloqueo.

process.on('unhandledRejection', (error, p) => {
  console.log('=== UNHANDLED REJECTION ===');
  console.dir(error.stack);
});
joshuakcockrell
fuente
La única diferencia funcional es hacer un console.dir en la propiedad de pila del error. Toda una diferencia en la producción en comparación con la respuesta aceptada.
Joshuakcockrell