try nodejs node handling errores error catch node.js exception-handling serverside-javascript

nodejs - Manejo de Excepciones de Mejores Prácticas de Node.js



try catch javascript (10)

Actualización: Joyent ahora tiene su propia guía mencionada en esta respuesta . La siguiente información es más de un resumen:

De forma segura "tirando" errores

Idealmente, nos gustaría evitar los errores no detectados tanto como sea posible, como tal, en lugar de lanzar el error literalmente, en cambio podemos "lanzar" el error de forma segura usando uno de los siguientes métodos, dependiendo de la arquitectura de nuestro código:

  • Para el código síncrono, si ocurre un error, devuelva el error:

    // Define divider as a syncrhonous function var divideSync = function(x,y) { // if error condition? if ( y === 0 ) { // "throw" the error safely by returning it return new Error("Can''t divide by zero") } else { // no error occured, continue on return x/y } } // Divide 4/2 var result = divideSync(4,2) // did an error occur? if ( result instanceof Error ) { // handle the error safely console.log(''4/2=err'', result) } else { // no error occured, continue on console.log(''4/2=''+result) } // Divide 4/0 result = divideSync(4,0) // did an error occur? if ( result instanceof Error ) { // handle the error safely console.log(''4/0=err'', result) } else { // no error occured, continue on console.log(''4/0=''+result) }

  • Para el código basado en la devolución de llamada (es decir, asíncrono), el primer argumento de la devolución de llamada es err , si ocurre un error err es el error, si no ocurre un error, err es null . Cualquier otro argumento sigue el argumento err :

    var divide = function(x,y,next) { // if error condition? if ( y === 0 ) { // "throw" the error safely by calling the completion callback // with the first argument being the error next(new Error("Can''t divide by zero")) } else { // no error occured, continue on next(null, x/y) } } divide(4,2,function(err,result){ // did an error occur? if ( err ) { // handle the error safely console.log(''4/2=err'', err) } else { // no error occured, continue on console.log(''4/2=''+result) } }) divide(4,0,function(err,result){ // did an error occur? if ( err ) { // handle the error safely console.log(''4/0=err'', err) } else { // no error occured, continue on console.log(''4/0=''+result) } })

  • Para el código de eventful , donde el error puede ocurrir en cualquier lugar, en lugar de lanzar el error, dispare el evento de error lugar :

    // Definite our Divider Event Emitter var events = require(''events'') var Divider = function(){ events.EventEmitter.call(this) } require(''util'').inherits(Divider, events.EventEmitter) // Add the divide function Divider.prototype.divide = function(x,y){ // if error condition? if ( y === 0 ) { // "throw" the error safely by emitting it var err = new Error("Can''t divide by zero") this.emit(''error'', err) } else { // no error occured, continue on this.emit(''divided'', x, y, x/y) } // Chain return this; } // Create our divider and listen for errors var divider = new Divider() divider.on(''error'', function(err){ // handle the error safely console.log(err) }) divider.on(''divided'', function(x,y,result){ console.log(x+''/''+y+''=''+result) }) // Divide divider.divide(4,2).divide(4,0)

Errores de "captura" de forma segura

Sin embargo, a veces, aún puede haber un código que arroje un error en alguna parte, lo que puede llevar a una excepción no detectada y un bloqueo potencial de nuestra aplicación si no la detectamos de forma segura. Dependiendo de nuestra arquitectura de código, podemos usar uno de los siguientes métodos para capturarlo:

  • Cuando sabemos dónde está ocurriendo el error, podemos ajustar esa sección en un dominio node.js

    var d = require(''domain'').create() d.on(''error'', function(err){ // handle the error safely console.log(err) }) // catch the uncaught errors in this asynchronous or synchronous code block d.run(function(){ // the asynchronous or synchronous code that we want to catch thrown errors on var err = new Error(''example'') throw err })

  • Si sabemos que el error está ocurriendo es un código síncrono, y por cualquier motivo no podemos usar dominios (quizás una versión anterior del nodo), podemos usar la declaración try catch:

    // catch the uncaught errors in this synchronous code block // try catch statements only work on synchronous code try { // the synchronous code that we want to catch thrown errors on var err = new Error(''example'') throw err } catch (err) { // handle the error safely console.log(err) }

    Sin embargo, tenga cuidado de no usar try...catch en código asíncrono, ya que no se try...catch un error de ejecución asíncrona:

    try { setTimeout(function(){ var err = new Error(''example'') throw err }, 1000) } catch (err) { // Example error won''t be caught here... crashing our app // hence the need for domains }

    Si desea trabajar con try..catch junto con el código asíncrono, cuando ejecute el Nodo 7.4 o superior, puede usar async/await forma nativa para escribir sus funciones asíncronas.

    Otra cosa con la que debe tener cuidado al try...catch es el riesgo de ajustar su devolución de llamada de finalización dentro de la declaración de try , de este modo:

    var divide = function(x,y,next) { // if error condition? if ( y === 0 ) { // "throw" the error safely by calling the completion callback // with the first argument being the error next(new Error("Can''t divide by zero")) } else { // no error occured, continue on next(null, x/y) } } var continueElsewhere = function(err, result){ throw new Error(''elsewhere has failed'') } try { divide(4, 2, continueElsewhere) // ^ the execution of divide, and the execution of // continueElsewhere will be inside the try statement } catch (err) { console.log(err.stack) // ^ will output the "unexpected" result of: elsewhere has failed }

    Este gotcha es muy fácil de hacer ya que su código se vuelve más complejo. Como tal, es mejor usar dominios o devolver errores para evitar (1) excepciones no detectadas en el código asíncrono (2) la ejecución de captura de captura de prueba que no desea. En los idiomas que permiten un subprocesamiento adecuado en lugar del estilo asíncrono de máquina de eventos de JavaScript, esto no es tan problemático.

  • Finalmente, en el caso de que ocurra un error no capturado en un lugar que no esté envuelto en un dominio o una declaración try catch, podemos hacer que nuestra aplicación no se bloquee al usar el escucha de uncaughtException (sin embargo, hacerlo puede poner la aplicación en un lugar desconocido). estado ):

    // catch the uncaught errors that weren''t wrapped in a domain or try catch statement // do not use this in modules, but only in applications, as otherwise we could have multiple of these bound process.on(''uncaughtException'', function(err) { // handle the error safely console.log(err) }) // the asynchronous or synchronous code that emits the otherwise uncaught error var err = new Error(''example'') throw err

Acabo de empezar a probar node.js hace unos días. Me he dado cuenta de que el nodo se termina cada vez que tengo una excepción no controlada en mi programa. Esto es diferente al contenedor del servidor normal al que he estado expuesto, donde solo muere el subproceso de trabajo cuando se producen excepciones no manejadas y el contenedor aún podría recibir la solicitud. Esto plantea algunas preguntas:

  • ¿ process.on(''uncaughtException'') la única forma efectiva de protegerse contra él?
  • ¿ process.on(''uncaughtException'') detectará la excepción no controlada durante la ejecución de procesos asíncronos?
  • ¿Hay algún módulo que ya esté creado (como enviar un correo electrónico o escribir en un archivo) que pueda aprovechar en caso de excepciones no detectadas?

Apreciaría cualquier puntero / artículo que me muestre las mejores prácticas comunes para el manejo de excepciones no detectadas en node.js


Escribí sobre esto recientemente en http://snmaynard.com/2012/12/21/node-error-handling/ . Una nueva característica del nodo en la versión 0.8 es dominios y le permite combinar todas las formas de manejo de errores en una forma más fácil de administrar. Puedes leer sobre ellos en mi post.

También puedes usar algo como Bugsnag para rastrear tus excepciones no detectadas y recibir notificaciones por correo electrónico, sala de chat o un ticket creado para una excepción no detectada (soy el co-fundador de Bugsnag).


Lo siguiente es un resumen y una curación de muchas fuentes diferentes sobre este tema, incluido el ejemplo de código y citas de publicaciones de blog seleccionadas. La lista completa de las mejores prácticas se puede encontrar aquí.

Mejores prácticas de manejo de errores Node.JS

Número 1: uso de promesas para el manejo de errores asíncronos

TL; DR: el manejo de errores asíncronos en el estilo de devolución de llamada es probablemente la forma más rápida de llegar al infierno (también conocida como la pirámide de la fatalidad). El mejor regalo que puedes darle a tu código es, en cambio, utilizar una biblioteca de promesas de buena reputación que proporciona una sintaxis de código muy compacta y familiar, como la captura de prueba

De lo contrario: el estilo de devolución de llamada Node.JS, función (error, respuesta), es una forma prometedora de código no mantenible debido a la combinación de manejo de errores con código casual, anidación excesiva y patrones de codificación incómodos.

Ejemplo de código - bueno

doWork() .then(doWork) .then(doError) .then(doWork) .catch(errorHandler) .then(verify);

código de ejemplo anti patrón - manejo de errores de estilo de devolución de llamada

getData(someParameter, function(err, result){ if(err != null) //do something like calling the given callback function and pass the error getMoreData(a, function(err, result){ if(err != null) //do something like calling the given callback function and pass the error getMoreData(b, function(c){ getMoreData(d, function(e){ ... }); }); }); }); });

Cita del blog: "Tenemos un problema con las promesas" (Del blog pouchdb, clasificado 11 para las palabras clave "Node Promises")

"... Y de hecho, las devoluciones de llamada hacen algo aún más siniestro: nos privan de la pila, que es algo que solemos dar por sentado en los lenguajes de programación. Escribir código sin una pila es muy parecido a conducir un coche sin pedal de freno: usted no se da cuenta de lo mal que lo necesita, hasta que lo alcanza y no está allí. El punto central de las promesas es devolvernos los fundamentos del lenguaje que perdimos cuando fuimos asíncronos: regresar, lanzar y la pila. Pero usted Hay que saber usar correctamente las promesas para poder aprovecharlas " .

Número2: Utilice solo el objeto de error incorporado

TL; DR: Es bastante común ver un código que arroja errores como una cadena o como un tipo personalizado, lo que complica la lógica de manejo de errores y la interoperabilidad entre los módulos. Ya sea que rechace una promesa, lance una excepción o emita un error, el uso del objeto Error incorporado en Node.JS aumenta la uniformidad y evita la pérdida de información de errores

De lo contrario: al ejecutar algún módulo, no está seguro de qué tipo de errores se reciben a cambio, lo que hace que sea mucho más difícil razonar acerca de la próxima excepción y manejarla. Incluso vale la pena, ¡el uso de tipos personalizados para describir errores puede llevar a la pérdida de información de errores críticos como el seguimiento de la pila!

Ejemplo de código - hacerlo bien

//throwing an Error from typical function, whether sync or async if(!productToAdd) throw new Error("How can I add new product when no value provided?"); //''throwing'' an Error from EventEmitter const myEmitter = new MyEmitter(); myEmitter.emit(''error'', new Error(''whoops!'')); //''throwing'' an Error from a Promise return new promise(function (resolve, reject) { DAL.getProduct(productToAdd.id).then((existingProduct) =>{ if(existingProduct != null) return reject(new Error("Why fooling us and trying to add an existing product?"));

ejemplo de código anti patrón

//throwing a String lacks any stack trace information and other important properties if(!productToAdd) throw ("How can I add new product when no value provided?");

Cita del blog: "Una cadena no es un error" (Del artículo del blog, en el puesto 6 para las palabras clave "Objeto de error Node.JS")

"... pasar una cadena en lugar de un error da como resultado una interoperabilidad reducida entre los módulos. Rompe los contratos con las API que podrían estar realizando instancias de verificación de errores, o que quieren saber más sobre el error . Los objetos de error, como veremos, tienen muchos Propiedades interesantes en los modernos motores de JavaScript, además de mantener el mensaje pasado al constructor. "

Número3: Distinguir errores operacionales vs programadores

TL; DR: los errores de operaciones (p. Ej., La API recibió una entrada no válida) se refieren a casos conocidos en los que el impacto del error se entiende completamente y se puede manejar de manera reflexiva. Por otro lado, el error del programador (por ejemplo, tratar de leer una variable no definida) se refiere a fallas de código desconocidas que dictan para reiniciar la aplicación correctamente.

De lo contrario: siempre puede reiniciar la aplicación cuando aparece un error, pero ¿por qué dejar de ~ 5000 usuarios en línea a causa de un error menor y predicho (error operacional)? lo contrario tampoco es lo ideal: mantener la aplicación activa cuando se produce un problema desconocido (error del programador) puede provocar un comportamiento impredecible. Diferenciar los dos permite actuar con tacto y aplicar un enfoque equilibrado basado en el contexto dado

Ejemplo de código - hacerlo bien

//throwing an Error from typical function, whether sync or async if(!productToAdd) throw new Error("How can I add new product when no value provided?"); //''throwing'' an Error from EventEmitter const myEmitter = new MyEmitter(); myEmitter.emit(''error'', new Error(''whoops!'')); //''throwing'' an Error from a Promise return new promise(function (resolve, reject) { DAL.getProduct(productToAdd.id).then((existingProduct) =>{ if(existingProduct != null) return reject(new Error("Why fooling us and trying to add an existing product?"));

Ejemplo de código: marcar un error como operativo (de confianza)

//marking an error object as operational var myError = new Error("How can I add new product when no value provided?"); myError.isOperational = true; //or if you''re using some centralized error factory (see other examples at the bullet "Use only the built-in Error object") function appError(commonType, description, isOperational) { Error.call(this); Error.captureStackTrace(this); this.commonType = commonType; this.description = description; this.isOperational = isOperational; }; throw new appError(errorManagement.commonErrors.InvalidInput, "Describe here what happened", true); //error handling code within middleware process.on(''uncaughtException'', function(error) { if(!error.isOperational) process.exit(1); });

Cita del blog : "De lo contrario, se arriesga al estado" (Del blog depurable, clasificado 3 para las palabras clave "Node.JS excepción no detectada")

" ... Por la naturaleza misma de cómo funciona el lanzamiento en JavaScript, casi nunca hay una manera de" retomar donde lo dejó "de manera segura, sin filtrar referencias, o crear algún otro tipo de estado frágil indefinido. La forma más segura de responder un error es apagar el proceso . Por supuesto, en un servidor web normal, es posible que tenga muchas conexiones abiertas y no es razonable cerrarlas repentinamente porque otra persona activó un error. El mejor enfoque es enviar una respuesta de error a la solicitud que provocó el error, mientras que deja que los demás terminen en su tiempo normal y dejar de escuchar nuevas solicitudes en ese trabajador "

Número 4: Maneja los errores de forma centralizada, pero no dentro del middleware

TL; DR: La lógica de manejo de errores, como el correo a admin y el registro, debe encapsularse en un objeto dedicado y centralizado al que todos los puntos finales (por ejemplo, middleware Express, trabajos cron, pruebas de unidad) llaman cuando se produce un error.

De lo contrario: no manejar los errores en un solo lugar dará lugar a la duplicación del código y, probablemente, a errores que se manejan incorrectamente

Ejemplo de código - un flujo de error típico

//DAL layer, we don''t handle errors here DB.addDocument(newCustomer, (error, result) => { if (error) throw new Error("Great error explanation comes here", other useful parameters) }); //API route code, we catch both sync and async errors and forward to the middleware try { customerService.addNew(req.body).then(function (result) { res.status(200).json(result); }).catch((error) => { next(error) }); } catch (error) { next(error); } //Error handling middleware, we delegate the handling to the centrzlied error handler app.use(function (err, req, res, next) { errorHandler.handleError(err).then((isOperationalError) => { if (!isOperationalError) next(err); }); });

Cita del blog: "A veces, los niveles más bajos no pueden hacer nada útil, excepto propagar el error a su interlocutor" (Del blog Joyent, clasificado 1 para las palabras clave "Manejo de errores Node.JS")

"... Puede terminar manejando el mismo error en varios niveles de la pila. Esto sucede cuando los niveles más bajos no pueden hacer nada útil, excepto propagar el error a su interlocutor, lo que propaga el error a su interlocutor, y así sucesivamente. A menudo, solo la persona que llama de nivel superior sabe cuál es la respuesta adecuada, ya sea para volver a intentar la operación, informar un error al usuario u otra cosa. Pero eso no significa que deba intentar informar todos los errores a un solo nivel superior devolución de llamada, porque esa devolución de llamada en sí misma no puede saber en qué contexto ocurrió el error "

Número 5: Documentar los errores de la API utilizando Swagger

TL; DR: Permita que sus interlocutores de la API sepan qué errores pueden surgir a cambio para que puedan manejarlos cuidadosamente sin fallar. Esto se hace generalmente con marcos de documentación de API REST como Swagger

De lo contrario: un cliente de API podría decidir bloquearse y reiniciarse solo porque recibió un error que no pudo entender. Nota: el llamador de su API podría ser usted (muy típico en un entorno de microservicios)

Cita del blog: "Debe informar a las personas que llaman qué errores pueden ocurrir" (Del blog Joyent, clasificado 1 para las palabras clave "Node.JS logging")

... Hemos hablado sobre cómo manejar los errores, pero cuando está escribiendo una nueva función, ¿cómo entrega los errores al código que llamó a su función? ... Si no sabe qué errores pueden ocurrir o no sabe qué significan, entonces su programa no puede ser correcto, excepto por accidente. Entonces, si está escribiendo una nueva función, debe informar a las personas que llaman qué errores pueden ocurrir y qué es lo que pueden hacer.

Número 6: cierra el proceso con gracia cuando un extraño llega a la ciudad

TL; DR: cuando se produce un error desconocido (un error del desarrollador, consulte el número 3 de la mejor práctica): existe incertidumbre acerca de la integridad de la aplicación. Una práctica común sugiere reiniciar el proceso con cuidado utilizando una herramienta de ''reinicio'' como Forever y PM2

De lo contrario: cuando se captura una excepción desconocida, es posible que algún objeto se encuentre en un estado defectuoso (por ejemplo, un emisor de eventos que se usa globalmente y que ya no dispare eventos debido a algún fallo interno) y todas las solicitudes futuras pueden fallar o comportarse de manera loca

Ejemplo de código: decidir si bloquearse

//deciding whether to crash when an uncaught exception arrives //Assuming developers mark known operational errors with error.isOperational=true, read best practice #3 process.on(''uncaughtException'', function(error) { errorManagement.handler.handleError(error); if(!errorManagement.handler.isTrustedError(error)) process.exit(1) }); //centralized error handler encapsulates error-handling related logic function errorHandler(){ this.handleError = function (error) { return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError); } this.isTrustedError = function(error) { return error.isOperational; }

Cita del blog: "Hay tres escuelas de pensamientos sobre el manejo de errores" (Del blog jsrecipes)

... Existen principalmente tres escuelas de pensamientos sobre el manejo de errores: 1. Deje que la aplicación se bloquee y reiníciela. 2. Manejar todos los errores posibles y nunca fallar. 3. Enfoque equilibrado entre los dos.

Número 7: usar un registrador maduro para aumentar la visibilidad de los errores

TL; DR: un conjunto de herramientas de registro maduras como Winston, Bunyan o Log4J, acelerará el descubrimiento y la comprensión de errores. Así que olvídate de console.log.

De lo contrario, hojear con console.logs o manualmente a través de un archivo de texto desordenado sin consultar las herramientas o un visor de registros decente puede mantenerlo ocupado en el trabajo hasta tarde.

Ejemplo de código - Winston logger en acción

//your centralized logger object var logger = new winston.Logger({ level: ''info'', transports: [ new (winston.transports.Console)(), new (winston.transports.File)({ filename: ''somefile.log'' }) ] }); //custom code somewhere using the logger logger.log(''info'', ''Test Log Message with some parameter %s'', ''some parameter'', { anything: ''This is metadata'' });

Cita del blog: "Permite identificar algunos requisitos (para un registrador):" (Del blog strongblog)

… Permite identificar algunos requisitos (para un registrador): 1. Marca de tiempo en cada línea de registro. Esta es bastante autoexplicativa: debería poder saber cuándo ocurrió cada entrada de registro. 2. El formato de registro debe ser fácilmente digerible por los humanos y las máquinas. 3. Permite múltiples flujos de destino configurables. Por ejemplo, puede estar escribiendo registros de seguimiento en un archivo, pero cuando se encuentra un error, escriba en el mismo archivo, luego en el archivo de error y envíe un correo electrónico al mismo tiempo ...

Número 8: descubra errores y tiempo de inactividad utilizando productos APM

TL; DR: los productos de monitoreo y rendimiento (también conocido como APM) miden de forma proactiva su base de código o API para que puedan resaltar de forma automática los errores, bloqueos y partes lentas que faltaba

De lo contrario: podría dedicar un gran esfuerzo a medir el rendimiento de la API y los tiempos de inactividad, probablemente nunca se dará cuenta de cuáles son las partes de código más lentas en el escenario del mundo real y cómo éstas afectan la UX.

Cita del blog: "Segmentos de productos APM" (Del blog Yoni Goldberg)

"... Los productos de APM constituyen 3 segmentos principales: 1. Monitoreo de sitios web o API: servicios externos que monitorean constantemente el tiempo de actividad y el rendimiento a través de solicitudes HTTP. Se pueden configurar en pocos minutos. A continuación se incluyen algunos candidatos seleccionados: Pingdom, Uptime Robot y New Relic 2 . Instrumentación de códigos: familia de productos que requieren integrar un agente dentro de la aplicación para beneficiarse de la detección lenta de códigos, estadísticas de excepciones, monitoreo de rendimiento y muchos más. A continuación, se incluyen algunos candidatos seleccionados: New Relic, App Dynamics 3. Tablero de instrumentos de inteligencia operacional: esta línea Los productos se centran en facilitar al equipo de operaciones con métricas y contenido curado que ayuda a mantenerse al tanto del rendimiento de la aplicación. Esto generalmente implica la agregación de múltiples fuentes de información (registros de aplicaciones, registros de base de datos, registros de servidores, etc.) y diseño de panel de control directo. Los siguientes son algunos de los candidatos seleccionados: Datadog, Splunk "

La anterior es una versión abreviada; consulte aquí más prácticas recomendadas y ejemplos.



Una instancia donde el uso de un try-catch podría ser apropiado es cuando se usa un bucle forEach. Es síncrono, pero al mismo tiempo no puede utilizar una declaración de retorno en el ámbito interno. En su lugar, se puede utilizar un enfoque de prueba y captura para devolver un objeto Error en el ámbito apropiado. Considerar:

function processArray() { try { [1, 2, 3].forEach(function() { throw new Error(''exception''); }); } catch (e) { return e; } }

Es una combinación de los enfoques descritos anteriormente en @balupton.


Los dominios nodejs es la forma más actualizada de manejar los errores en nodejs. Los dominios pueden capturar tanto errores / otros eventos como objetos lanzados tradicionalmente. Los dominios también proporcionan funcionalidad para el manejo de devoluciones de llamada con un error pasado como primer argumento a través del método de intercepción.

Al igual que con el manejo normal de errores de estilo try / catch, generalmente es mejor cometer errores cuando ocurren, y bloquear las áreas en las que desea aislar los errores para que no afecten al resto del código. La forma de "bloquear" estas áreas es llamar a domain.run con una función como un bloque de código aislado.

En el código síncrono, lo anterior es suficiente: cuando ocurre un error, dejas que se lance o lo atrapas y manejas allí, revirtiendo los datos que necesitas revertir.

try { //something } catch(e) { // handle data reversion // probably log too }

Cuando se produce el error en una devolución de llamada asíncrona, debe ser capaz de manejar completamente la reversión de datos (estado compartido, datos externos como bases de datos, etc.). O tiene que establecer algo para indicar que ha ocurrido una excepción: donde quiera que le importe ese indicador, debe esperar a que se complete la devolución de llamada.

var err = null; var d = require(''domain'').create(); d.on(''error'', function(e) { err = e; // any additional error handling } d.run(function() { Fiber(function() { // do stuff var future = somethingAsynchronous(); // more stuff future.wait(); // here we care about the error if(err != null) { // handle data reversion // probably log too } })});

Parte de ese código anterior es feo, pero puedes crear patrones para hacerlo más bonito, por ejemplo:

var specialDomain = specialDomain(function() { // do stuff var future = somethingAsynchronous(); // more stuff future.wait(); // here we care about the error if(specialDomain.error()) { // handle data reversion // probably log too } }, function() { // "catch" // any additional error handling });

ACTUALIZACIÓN (2013-09):

Arriba, uso un futuro que implica fibras semánticas , que le permiten esperar futuros en línea. En realidad, esto le permite utilizar los bloques tradicionales de captura y prueba para todo , lo que me parece la mejor manera de hacerlo. Sin embargo, no siempre puedes hacer esto (es decir, en el navegador) ...

También hay futuros que no requieren semántica de fibras (que luego funcionan con JavaScript normal y de navegación). Estos pueden llamarse futuros, promesas o diferidos (me referiré a futuros a partir de aquí). Las bibliotecas de futuros simples de JavaScript permiten que los errores se propaguen entre futuros. Solo algunas de estas bibliotecas permiten que cualquier futuro lanzado sea manejado correctamente, así que ten cuidado.

Un ejemplo:

returnsAFuture().then(function() { console.log(''1'') return doSomething() // also returns a future }).then(function() { console.log(''2'') throw Error("oops an error was thrown") }).then(function() { console.log(''3'') }).catch(function(exception) { console.log(''handler'') // handle the exception }).done()

Esto imita un try-catch normal, aunque las piezas son asíncronas. Se imprimiría:

1 2 handler

Tenga en cuenta que no imprime ''3'' porque se lanzó una excepción que interrumpe ese flujo.

Echa un vistazo a las promesas del pájaro azul:

Tenga en cuenta que no he encontrado muchas otras bibliotecas distintas a estas que manejan adecuadamente las excepciones lanzadas. jQuery aplazado, por ejemplo, no: el manejador de "fallar" nunca obtendría la excepción lanzada por un manejador ''entonces'', que en mi opinión es un factor decisivo.


La detección de errores ha sido muy bien discutida aquí, pero vale la pena recordar cerrar los errores en algún lugar para que puedas verlos y arreglarlos.

Bunyan es un marco de trabajo de registro popular para NodeJS; es compatible con la escritura en un montón de lugares de salida diferentes, lo que lo hace útil para la depuración local, siempre que evite console.log. En el controlador de errores de su dominio, podría escupir el error a un archivo de registro.

var log = bunyan.createLogger({ name: ''myapp'', streams: [ { level: ''error'', path: ''/var/tmp/myapp-error.log'' // log ERROR to this file } ] });

Esto puede llevarle mucho tiempo si tiene muchos errores y / o servidores para verificar, por lo que podría valer la pena buscar una herramienta como Raygun (descargo de responsabilidad, trabajo en Raygun) para agrupar los errores, o usarlos a la vez. Si decidió utilizar Raygun como herramienta, también es bastante fácil de configurar.

var raygunClient = new raygun.Client().init({ apiKey: ''your API key'' }); raygunClient.send(theError);

Al cruzarse con el uso de una herramienta como PM2 o ​​para siempre, su aplicación debería poder bloquearse, cerrar sesión y reiniciar sin ningún problema importante.


Después de leer este post hace algún tiempo, me preguntaba si sería seguro usar dominios para el manejo de excepciones en un nivel de api / función. Quería usarlos para simplificar el código de manejo de excepciones en cada función asíncrona que escribí. Mi preocupación era que el uso de un nuevo dominio para cada función generaría una sobrecarga significativa. Mi tarea parece indicar que hay una sobrecarga mínima y que el rendimiento es mejor con dominios que con captura de prueba en algunas situaciones.

http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/



Solo me gustaría agregar que la biblioteca Step.js lo ayuda a manejar las excepciones al pasarlas siempre a la función del siguiente paso. Por lo tanto, puede tener como último paso una función que verifique si hay errores en cualquiera de los pasos anteriores. Este enfoque puede simplificar enormemente su manejo de errores.

A continuación hay una cita de la página de github:

Las excepciones lanzadas se capturan y pasan como primer argumento a la siguiente función. Siempre que no anide las funciones de devolución de llamada en línea sus funciones principales, esto evitará que haya excepciones no detectadas. Esto es muy importante para los servidores node.JS de larga ejecución, ya que una única excepción no detectada puede hacer que todo el servidor se caiga.

Además, puede usar Step para controlar la ejecución de scripts para tener una sección de limpieza como último paso. Por ejemplo, si desea escribir un script de compilación en Nodo e informar el tiempo de escritura, el último paso puede hacerlo (en lugar de intentar extraer la última devolución de llamada).