Gérer des erreurs spécifiques dans JavaScript (pensez aux exceptions)

112

Comment implémenteriez-vous différents types d'erreurs, pour pouvoir en détecter certaines et en laisser d'autres bouillonner…?

Une façon d'y parvenir est de modifier le prototype de l' Errorobjet:

Error.prototype.sender = "";


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

    e.sender = "specific";

    throw e;
}

Attraper une erreur spécifique:

try
{
    throwSpecificError();
}

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

    // handle specific error
}


Avez-vous des alternatives?

cllpse
la source

Réponses:

159

Pour créer des exceptions personnalisées, vous pouvez hériter de l'objet 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
  }
}

Une approche minimaliste, sans hériter d'Erreur, pourrait être de lancer un objet simple ayant un nom et des propriétés de message:

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
la source
2
Hériter de Errora des problèmes. Voir stackoverflow.com/questions/1382107/…
Crescent Fresh
5
le problème avec ce code: } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }c'est qu'il ne fonctionnera pas dans IE7, ce qui soulève l'erreur «Exception levée et non interceptée». Voici l'explication extrêmement stupide (comme toujours) de msdn: "Vous avez inclus une instruction throw, mais elle n'était pas incluse dans un bloc try, ou il n'y avait pas de bloc catch associé pour intercepter l'erreur. Des exceptions sont levées depuis le bloc try. en utilisant l'instruction throw, et intercepté en dehors du bloc try avec une instruction catch. "
Eugene Kuzmenko
1
Eh bien, le C # de Microsoft gère certainement mieux les erreurs que Javascript: P. Mozzilla a ajouté quelque chose comme ça à Firefox, c'est comme ça. Bien que ce ne soit pas dans le standard Ecmascript, pas même ES6, mais ils expliquent également comment le rendre conforme, bien que ce ne soit pas aussi succinct. Fondamentalement comme ci-dessus, mais en utilisant instanceOf. Vérifiez ici
Bart
En Javascript, vous pouvez lancer ce que vous voulez, que ce soit une simple chaîne, un nombre (pensez code d'erreur) ou un objet pleinement qualifié. Doux!
Abraham Brookes
1
@LuisNell, Si vous regardez attentivement mon exemple de code, vous verrez que je ne suggérais pas d'utiliser la namepropriété de la fonction constructeur. Je suggérais de jeter un objet sur mesure avec une namepropriété, qui ne se cassera pas ...
CMS
15

Comme indiqué dans les commentaires ci-dessous, cela est spécifique à Mozilla, mais vous pouvez utiliser des blocs de «capture conditionnelle». par exemple:

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;
} 

Cela donne quelque chose de plus proche de la gestion des exceptions typées utilisée en Java, au moins syntaxiquement.

Andy
la source
Combinez avec la réponse de CMS et c'est parfait.
Ates Goral
3
La capture conditionnelle est quelque chose que je ne savais pas plus tôt ou que j'avais oublié. Merci de m'avoir informé / rappelé! +1
Ates Goral
12
Uniquement pris en charge par Firefox (depuis 2.0). Il n'analyse même pas dans d'autres navigateurs; vous n'obtenez que des erreurs de syntaxe.
Crescent Fresh
10
Oui, il s'agit d'une extension uniquement Mozilla, elle n'est même pas proposée pour la standardisation. Étant une fonctionnalité au niveau de la syntaxe, il n'y a aucun moyen de la détecter et de l'utiliser éventuellement non plus.
bobince
3
En complément, la solution proposée étant non standard. Citation de la [Référence 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

En utilisant try-catch-finally.js , vous pouvez appeler la _tryfonction avec un rappel anonyme, qu'elle appellera, et vous pouvez enchaîner les .catchappels pour intercepter des erreurs spécifiques, et un .finallyappel pour exécuter dans les deux cas.

Exemple

_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');
});

Exemple avec des fonctions fléchées modernes et des littéraux de modèle

_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
la source
2

Module pour l'utilisation d'exportation

/**
 * 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
};

Importer dans le script:

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

Utilisation:

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

Indicatif d'appel externe:

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
la source
0

Je n'aimais aucune de ces solutions alors j'ai créé la mienne. Le try-catch-finally.js est plutôt cool sauf que si vous oubliez un petit trait de soulignement (_) avant l'essai, le code fonctionnera toujours très bien, mais rien ne sera jamais attrapé! Beurk.

CatchFilter

J'ai ajouté un CatchFilter dans mon code:

"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;
    }
  };
};

Maintenant je peux filtrer

Maintenant, je peux filtrer comme en C # ou 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
la source
-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
la source
Bonjour, bienvenue sur StackOverflow. Comment votre réponse est-elle meilleure / plus efficace / etc à partir des 5 autres réponses déjà publiées?
mjuarez le