¿Por qué no puedo simplemente lanzar una Errordevolución de llamada dentro de la captura y dejar que el proceso maneje el error como si estuviera en cualquier otro ámbito?
Si no hago console.log(err)nada, se imprime y no sé nada de lo que sucedió. El proceso acaba de terminar ...
Ejemplo:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
Si las devoluciones de llamada se ejecutan en el hilo principal, ¿por qué Errorse traga un agujero negro?
javascript
asynchronous
promise
throw
es6-promise
demian85
fuente
fuente

.catch(…)vuelve..catch((e) => { throw new Error() }), escribir.catch((e) => { return Promise.reject(new Error()) })o simplemente.catch((e) => Promise.reject(new Error()))Respuestas:
Como otros han explicado, el "agujero negro" se debe a que arrojar dentro de una
.catchcadena continúa con una promesa rechazada, y no tiene más capturas, lo que lleva a una cadena no terminada, que traga errores (¡malo!)Agregue una captura más para ver qué sucede:
Una captura en el medio de una cadena es útil cuando desea que la cadena continúe a pesar de un paso fallido, pero un relanzamiento es útil para continuar fallando después de hacer cosas como el registro de información o los pasos de limpieza, tal vez incluso alterando qué error es aventado.
Truco
Para hacer que el error aparezca como un error en la consola web, como originalmente pretendías, utilizo este truco:
Incluso los números de línea sobreviven, por lo que el enlace en la consola web me lleva directamente al archivo y la línea donde ocurrió el error (original).
Por que funciona
Cualquier excepción en una función llamada como cumplimiento de promesa o controlador de rechazo se convierte automáticamente en un rechazo de la promesa que se supone que debe devolver. El código de promesa que llama a su función se encarga de esto.
Una función llamada por setTimeout, por otro lado, siempre se ejecuta desde el estado estable de JavaScript, es decir, se ejecuta en un nuevo ciclo en el bucle de eventos de JavaScript. Las excepciones no están atrapadas por nada y llegan a la consola web. Dado que
errcontiene toda la información sobre el error, incluida la pila original, el archivo y el número de línea, aún se informa correctamente.fuente
function logErrors(e){console.error(e)}luego úsalo comodo1().then(do2).catch(logErrors). La respuesta en sí es genial por cierto, +1window.onerrorcontrolador de eventos. Solo haciendo elsetTimeouttruco se puede hacer esto. Dewindow.onerrorlo contrario , nunca escuchará nada sobre los errores ocurridos en Promise.console.logopostErrorToServer, simplemente puedes hacer lo que hay que hacer. No hay ninguna razón por la que el código que se encuentrawindow.onerrorno se pueda descomponer en una función separada y se llame desde 2 lugares. Probablemente sea incluso más corto que lasetTimeoutlínea.Cosas importantes para entender aquí
Ambas funciones
thenycatchdevuelven nuevos objetos de promesa.Ya sea arrojando o rechazando explícitamente, se moverá la promesa actual al estado rechazado.
Desde
thenycatchdevolver nuevos objetos de promesa, se pueden encadenar.Si arroja o rechaza dentro de un controlador de promesa (
thenocatch), se manejará en el siguiente controlador de rechazo por el camino de encadenamiento.Como mencionó jfriend00, los controladores
thenycatchno se ejecutan sincrónicamente. Cuando un controlador lanza, llegará a su fin de inmediato. Por lo tanto, la pila se desenrollará y se perderá la excepción. Es por eso que lanzar una excepción rechaza la promesa actual.En su caso, está rechazando dentro
do1arrojando unErrorobjeto. Ahora, la promesa actual estará en estado rechazado y el control se transferirá al siguiente controlador, que esthenen nuestro caso.Como el
thencontrolador no tiene un controlador de rechazo,do2no se ejecutará en absoluto. Puede confirmar esto usandoconsole.logdentro de él. Dado que la promesa actual no tiene un controlador de rechazo, también se rechazará con el valor de rechazo de la promesa anterior y el control se transferirá al siguiente controlador que seacatch.Como
catches un controlador de rechazo, cuando lo hacesconsole.log(err.stack);dentro de él, puedes ver el seguimiento de la pila de errores. Ahora, está arrojando unErrorobjeto para que la promesa devueltacatchtambién esté en estado rechazado.Como no ha adjuntado ningún controlador de rechazo al
catch, no puede observar el rechazo.Puedes dividir la cadena y entender esto mejor, así
La salida que obtendrás será algo así como
Dentro del
catchcontrolador 1, está obteniendo el valor delpromiseobjeto como rechazado.Del mismo modo, la promesa devuelta por el
catchcontrolador 1 también se rechaza con el mismo error con el quepromisese rechazó y la estamos observando en el segundocatchcontrolador.fuente
.then()controladores son asíncronos (la pila se desenrolla antes de que se ejecuten), por lo que las excepciones dentro de ellos deben convertirse en rechazos, de lo contrario no habría controladores de excepciones para atraparlos.Probé el
setTimeout()método detallado anteriormente ...Molesto, encontré que esto era completamente inestable. Debido a que arroja un error asincrónico, no puede envolverlo dentro de una
try/catchdeclaración, porquecatchhabrá dejado de escuchar cuando se produzca el error.Volví a usar un oyente que funcionó perfectamente y, debido a que es la forma en que se debe usar JavaScript, fue altamente comprobable.
fuente
De acuerdo con las especificaciones (ver 3.III.d) :
Eso significa que si arroja una excepción en la
thenfunción, se detectará y su promesa será rechazada.catchno tiene sentido aquí, es solo un atajo para.then(null, function() {})Supongo que desea registrar rechazos no controlados en su código. La mayoría de las bibliotecas promete un fuego
unhandledRejectionpara ello. Aquí está la esencia relevante con la discusión al respecto.fuente
unhandledRejectionenlace es para JavaScript del lado del servidor, en el lado del cliente, diferentes navegadores tienen diferentes soluciones. Todavía no lo hemos estandarizado, pero está llegando de manera lenta pero segura.Sé que esto es un poco tarde, pero me encontré con este hilo, y ninguna de las soluciones fue fácil de implementar para mí, así que se me ocurrió la mía:
Agregué una pequeña función auxiliar que devuelve una promesa, así:
Luego, si tengo un lugar específico en cualquiera de mi cadena de promesas donde quiero lanzar un error (y rechazar la promesa), simplemente regreso de la función anterior con mi error construido, así:
De esta manera tengo el control de lanzar errores adicionales desde dentro de la cadena de promesa. Si desea manejar también los errores de promesa 'normales', expandiría su captura para tratar los errores 'arrojados' por separado.
Espero que esto ayude, ¡es mi primera respuesta de stackoverflow!
fuente
Promise.reject(error)en lugar denew Promise(function (resolve, reject){ reject(error) })(que de todos modos necesitaría una declaración de devolución)Sí, promete errores de deglución, y solo puede detectarlos
.catch, como se explica con más detalle en otras respuestas. Si está en Node.js y desea reproducir elthrowcomportamiento normal , imprimiendo el seguimiento de la pila en la consola y el proceso de salida, puede hacerlofuente
unhandledRejectionevento