Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

244
Vistas
¿Por qué no puedo lanzar dentro de un controlador Promise.catch?

¿Por qué no puedo lanzar un Error dentro de la devolución de llamada catch y dejar que el proceso maneje el error como si estuviera en cualquier otro ámbito?

Si no hago console.log(err) no se imprime nada 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é el Error es tragado por un agujero negro?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Como han explicado otros, el "agujero negro" se debe a que arrojar dentro de un .catch continúa la cadena con una promesa rechazada, y no tiene más capturas, lo que lleva a una cadena sin terminar, que se traga los errores (¡malo!)

Agregue una captura más para ver qué está pasando:

 do1().then(do2).catch(function(err) { //console.log(err.stack); // This is the only way to see the stack throw err; // Where does this go? }).catch(function(err) { console.log(err.stack); // It goes here! });

Una captura en el medio de una cadena es útil cuando desea que la cadena continúe a pesar de un paso fallido, pero volver a lanzar 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 que el error aparezca como un error en la consola web, como pretendías originalmente, uso este truco:

 .catch(function(err) { setTimeout(function() { throw err; }); });

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 qué funciona

Cualquier excepción en una función llamada como controlador de rechazo o cumplimiento de promesa se convierte automáticamente en un rechazo de la promesa que se supone que debes 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 allí no son detectadas por nada y llegan a la consola web. Dado que err contiene toda la información sobre el error, incluida la pila original, el archivo y el número de línea, todavía se informa correctamente.

over 4 years ago · Santiago Trujillo Denunciar

0

Cosas importantes para entender aquí

  1. Tanto las funciones then como catch devuelven nuevos objetos de promesa.

  2. Ya sea lanzando o rechazando explícitamente, moverá la promesa actual al estado rechazado.

  3. Desde then y catch devolver nuevos objetos de promesa, se pueden encadenar.

  4. Si arroja o rechaza dentro de un controlador de promesa ( then o catch ), se manejará en el siguiente controlador de rechazo en la ruta de encadenamiento.

  5. Como menciona jfriend00, los controladores then y catch no se ejecutan sincrónicamente. Cuando un manejador lanza, terminará inmediatamente. Entonces, la pila se desenrollará y la excepción se perdería. Es por eso que lanzar una excepción rechaza la promesa actual.


En su caso, está rechazando dentro de do1 lanzando un objeto Error . Ahora, la promesa actual estará en estado rechazado y el control then transferirá al siguiente controlador, que es nuestro caso.

Dado que el controlador then no tiene un controlador de rechazo, do2 no se ejecutará en absoluto. Puede confirmar esto usando console.log dentro 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 es catch .

Como catch es un controlador de rechazo, cuando haces console.log(err.stack); dentro de él, puede ver el seguimiento de la pila de errores. Ahora, está arrojando un objeto de Error , por lo que la promesa devuelta por catch también estará en estado rechazado.

Dado que no ha adjuntado ningún controlador de rechazo al catch , no puede observar el rechazo.


Puedes dividir la cadena y entender esto mejor, así

 var promise = do1().then(do2); var promise1 = promise.catch(function (err) { console.log("Promise", promise); throw err; }); promise1.catch(function (err) { console.log("Promise1", promise1); });

El resultado que obtendrá será algo así como

 Promise Promise { <rejected> [Error: do1] } Promise1 Promise { <rejected> [Error: do1] }

Dentro del controlador de catch 1, obtiene el valor del objeto de promise como rechazado.

De la misma forma, la promesa devuelta por el catch handler 1, también es rechazada con el mismo error con el que fue rechazada la promise y lo estamos observando en el segundo catch handler.

over 4 years ago · Santiago Trujillo Denunciar

0

Probé el método setTimeout() detallado arriba...

 .catch(function(err) { setTimeout(function() { throw err; }); });

Molesto, encontré que esto era completamente incomprobable. Debido a que está arrojando un error asíncrono, no puede envolverlo dentro de una instrucción try/catch , porque la catch habrá dejado de escuchar en el momento en que se arroje el error.

Volví a usar un oyente que funcionó perfectamente y, debido a que JavaScript debe usarse, era altamente comprobable.

 return new Promise((resolve, reject) => { reject("err"); }).catch(err => { this.emit("uncaughtException", err); /* Throw so the promise is still rejected for testing */ throw err; });
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda