Manejo de errores específicos en JavaScript (piense en excepciones)

112

¿Cómo implementaría diferentes tipos de errores para poder detectar algunos específicos y dejar que otros aparezcan?

Una forma de lograrlo es modificar el prototipo del Errorobjeto:

Error.prototype.sender = "";


function throwSpecificError()
{
    var e = new Error();

    e.sender = "specific";

    throw e;
}

Detectar error específico:

try
{
    throwSpecificError();
}

catch (e)
{
    if (e.sender !== "specific") throw e;

    // handle specific error
}


¿Tienen alguna alternativa, chicos?

cllpse
fuente

Respuestas:

159

Para crear excepciones personalizadas, puede heredar del objeto Error:

function SpecificError () {

}

SpecificError.prototype = new Error();

// ...
try {
  throw new SpecificError;
} catch (e) {
  if (e instanceof SpecificError) {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}

Un enfoque minimalista, sin heredar de Error, podría lanzar un objeto simple con un nombre y propiedades de mensaje:

function throwSpecificError() {
  throw {
    name: 'SpecificError',
    message: 'SpecificError occurred!'
  };
}


// ...
try {
  throwSpecificError();
} catch (e) {
  if (e.name == 'SpecificError') {
   // specific error
  } else {
    throw e; // let others bubble up
  }
}
CMS
fuente
2
Heredar de Errortiene problemas. Ver stackoverflow.com/questions/1382107/…
Crescent Fresh
5
el problema con este código: } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }es que no funcionará en IE7, lo que genera el error "Excepción lanzada y no detectada". A continuación se muestra la explicación extremadamente estúpida (como siempre) de msdn: "Incluyó una declaración de lanzamiento, pero no estaba incluida en un bloque de prueba, o no había un bloque de captura asociado para atrapar el error. Las excepciones se lanzan desde dentro del bloque de prueba usando la sentencia throw y capturado fuera del bloque try con una sentencia catch ".
Eugene Kuzmenko
1
Bueno, C # de Microsoft maneja los errores mejor que Javascript: P. Mozzilla agregó algo parecido a Firefox que es así. Aunque no está en el estándar Ecmascript, ni siquiera en ES6, pero también explican cómo hacerlo conforme, aunque no es tan sucinto. Básicamente igual que el anterior, pero usando instanceOf. Compruebe aquí
Bart
En Javascript puede lanzar lo que quiera, ya sea una cadena simple, un número (piense en un código de error) o un objeto completamente calificado. ¡Dulce!
Abraham Brookes
1
@LuisNell, si miras mi ejemplo de código con cuidado, verás que no estaba sugiriendo usar la namepropiedad de la función constructora. Estaba sugiriendo lanzar un objeto hecho a medida con una namepropiedad, que no se romperá ...
CMS
15

Como se indica en los comentarios a continuación, esto es específico de Mozilla, pero puede usar bloques de 'captura condicional'. p.ej:

try {
  ...
  throwSpecificError();
  ...
}
catch (e if e.sender === "specific") {
  specificHandler(e);
}
catch (e if e.sender === "unspecific") {
  unspecificHandler(e);
}
catch (e) {
  // don't know what to do
  throw e;
} 

Esto le da algo más parecido al manejo de excepciones escritas usado en Java, al menos sintácticamente.

Andy
fuente
Combine con la respuesta de CMS y es perfecto.
Ates Goral
3
La captura condicional es algo que no sabía antes o que me olvidé. ¡Gracias por educarme / recordarme! +1
Ates Goral
12
Solo es compatible con Firefox (desde 2.0). Ni siquiera analiza en otros navegadores; solo obtiene errores de sintaxis.
Crescent Fresh
10
Sí, esta es una extensión exclusiva de Mozilla, ni siquiera está propuesta para estandarización. Al ser una característica de nivel de sintaxis, no hay forma de rastrearla y, opcionalmente, usarla.
Bobince
3
Además, considerando que la solución propuesta no es estándar. Cita de la [Referencia de JavaScript de Mozilla [( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ):This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
informatik01
10

try-catch-finally.js

Utilizando try-catch-billion finalmente.js , puede llamar a la _tryfunción con una devolución de llamada anónima, a la que llamará, y puede encadenar .catchllamadas para detectar errores específicos y una .finallyllamada para ejecutar de cualquier manera.

Ejemplo

_try(function () {
    throw 'My error';
})
.catch(Error, function (e) {
    console.log('Caught Error: ' + e);
})
.catch(String, function (e) {
    console.log('Caught String: ' + e);
})
.catch(function (e) {
    console.log('Caught other: ' + e);
})
.finally(function () {
    console.log('Error was caught explicitly');
});

Ejemplo con funciones de flecha modernas y literales de plantilla

_try(() => {
  throw 'My error';
}).catch(Error, e => {
  console.log(`Caught Error: ${e}`);
}).catch(String, e => {
  console.log(`Caught String: ${e}`);
}).catch(e => {
  console.log(`Caught other: ${e}`);
}).finally(() => {
  console.log('Error was caught explicitly');
});
c24w
fuente
2

Módulo para uso de exportación

/**
 * Custom InputError
 */
class InputError extends Error {
  /**
   * Create InputError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom AuthError
 */
class AuthError extends Error {
  /**
   * Create AuthError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * Custom NotFoundError
 */
class NotFoundError extends Error {
  /**
   * Create NotFoundError
   * @param {String} message
   */
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = {
  InputError: InputError,
  AuthError: AuthError,
  NotFoundError: NotFoundError
};

Importar al script:

const {InputError, AuthError, NotFoundError} = require(path.join(process.cwd(), 'lib', 'errors'));

Utilizar:

function doTheCheck = () =>
  checkInputData().then(() => {
    return Promise.resolve();
  }).catch(err => {
    return Promise.reject(new InputError(err));
  });
};

Código de llamada externo:

doTheCheck.then(() => {
  res.send('Ok');
}).catch(err => {
  if (err instanceof NotFoundError) {
    res.status(404).send('Not found');
  } else if (err instanceof AuthError) {
    res.status(301).send('Not allowed');
  } else if (err instanceof InputError) {
    res.status(400).send('Input invalid');
  } else {
    console.error(err.toString());
    res.status(500).send('Server error');
  }
});
Hoovinator
fuente
0

No me gustó ninguna de estas soluciones, así que hice la mía. El try-catch-finalmente.js es bastante bueno, excepto que si olvidas un pequeño guión bajo (_) antes del intento, el código seguirá funcionando bien, ¡pero nunca se detectará nada! ¡Qué asco!

CatchFilter

Agregué un CatchFilter en mi código:

"use strict";

/**
 * This catches a specific error. If the error doesn't match the errorType class passed in, it is rethrown for a
 * different catch handler to handle.
 * @param errorType The class that should be caught
 * @param funcToCall The function to call if an error is thrown of this type
 * @return {Function} A function that can be given directly to the `.catch()` part of a promise.
 */
module.exports.catchOnly = function(errorType, funcToCall) {
  return (error) => {
    if(error instanceof errorType) {
      return funcToCall(error);
    } else {
      // Oops, it's not for us.
      throw error;
    }
  };
};

Ahora puedo filtrar

Ahora puedo filtrar como en C # o Java:

new Promise((resolve, reject => {
   <snip><snip>
}).catch(CatchFilter.catchOnly(MyError, err =>
   console.log("This is for my error");
}).catch(err => {
   console.log("This is for all of the other errors.");
});
Ryan Shillington
fuente
-2
    <li>
      <span>onWarning:</span>
      <span id="msg_warning"></span>
    </li>

  try {
  // load face detection model
  await changeFaceDetector(MTCNN)
  changeInputSize(128)

  // try to access users webcam and stream the images
  // to the video element

    const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
    const videoEl = $('#inputVideo').get(0)
    videoEl.srcObject = stream
  }
  catch(err) {
    //$("#msg_error").html(`Requested device not found`);
    $("#msg_error").html(err.message);
    console.log(err.message);
  }
carls eriksen
fuente
Hola, bienvenido a StackOverflow. ¿Cómo es su respuesta mejor / más eficiente / etc. de las otras 5 respuestas ya publicadas?
mjuarez