¿Por qué primer parámetro?
Debido a la naturaleza asincrónica de Node.js, el patrón de primer parámetro como err se ha establecido como una convención para el manejo de errores de Node.js de userland . Esto es porque asincrónico:
try {
setTimeout(function() {
throw 'something broke' //Some random error
}, 5)
}
catch(e) {
//Will never get caught
}
Por lo tanto, tener el primer argumento de la devolución de llamada es prácticamente la única forma sensata de pasar los errores de forma asincrónica que no sea simplemente lanzarlos.
Hacerlo resultará en algo unhandled exception
que, tal como suena, implica que no se hizo nada para sacar la aplicación de su estado confuso.
Excepciones, ¿por qué existen?
Sin embargo, vale la pena señalar que prácticamente todas las partes de Node.js son emisores de eventos y el lanzamiento de una excepción es un evento de bajo nivel que se puede manejar como todos los eventos:
//This won't immediately crash if connection fails
var socket = require("net").createConnection(5000);
socket.on("error", function(err) {
console.error("calm down...", err)
});
Esto puede, pero no debe, llevarse al extremo para detectar todos los errores y crear una aplicación que tratará de no bloquearse nunca. Esta es una idea terrible en casi todos los casos de uso, ya que dejará al desarrollador sin ninguna idea de lo que está sucediendo en el estado de la aplicación y es análogo al ajuste principal en try-catch.
Dominios - agrupando eventos lógicamente
Como parte de este problema de excepciones que hacen que las aplicaciones se caigan, los dominios permiten que el desarrollador tome, por ejemplo, la aplicación Express.js, e intente cerrar conexiones de manera sensata en caso de falla catastrófica.
ES6
Probablemente esté mencionando que esto cambiará nuevamente ya que ES6 permite que el patrón del generador cree eventos asincrónicos que todavía son atrapables con los bloques try / catch.
Koa (escrito por TJ Holowaychuck, el mismo autor original de Express.js) hace esto notablemente. Utiliza la yield
instrucción ES6 para crear bloques que, aunque parecen casi sincrónicos, se manejan de la manera asíncrona del nodo habitual:
app.use(function *(next) {
try {
yield next;
}
catch (err) {
this.status = err.status || 500;
this.body = err.message;
this.app.emit('error', err, this);
}
});
app.use(function *(next) {
throw new Error('some error');
})
Este ejemplo fue robado descaradamente de aquí .