Gestione di errori specifici in JavaScript (pensa alle eccezioni)


112

Come implementereste diversi tipi di errori, così sareste in grado di individuarne di specifici e lasciare che altri si ribollano ..?

Un modo per ottenere ciò è modificare il prototipo Errordell'oggetto:

Error.prototype.sender = "";


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

    e.sender = "specific";

    throw e;
}

Cattura errore specifico:

try
{
    throwSpecificError();
}

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

    // handle specific error
}


Ragazzi, avete delle alternative?

Risposte:


159

Per creare eccezioni personalizzate, puoi ereditare dall'oggetto 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 approccio minimalista, senza ereditare da Error, potrebbe essere il lancio di un semplice oggetto con un nome e proprietà del messaggio:

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

2
Ereditare da Errorha problemi. Vedi stackoverflow.com/questions/1382107/…
Crescent Fresh il

5
il problema con questo codice: } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }è che non funzionerà in IE7, sollevando l'errore "Eccezione generata e non rilevata". Di seguito è la spiegazione estremamente stupida (come sempre) da msdn: "Hai incluso un'istruzione throw, ma non è stata racchiusa in un blocco try, oppure non è stato associato alcun blocco catch per intercettare l'errore. Le eccezioni vengono generate all'interno del blocco try usando l'istruzione throw e catturato fuori dal blocco try con un'istruzione catch. "
Eugene Kuzmenko

1
Ebbene, il C # di Microsoft gestisce sicuramente gli errori meglio di Javascript: P. Mozzilla ha aggiunto qualcosa di simile a Firefox che è così. Sebbene non sia nello standard Ecmascript, nemmeno ES6, ma spiegano anche come renderlo conforme, anche se non è così succinto. Fondamentalmente come sopra, ma usando instanceOf. Controlla qui
Bart

In Javascript puoi lanciare quello che vuoi, che sia una semplice stringa, un numero (pensa al codice di errore) o un oggetto completo. Dolce!
Abraham Brookes

1
@LuisNell, se guardi attentamente il mio esempio di codice, vedrai che non stavo suggerendo di utilizzare la nameproprietà della funzione di costruzione. Stavo suggerendo di lanciare un oggetto personalizzato con una nameproprietà, che non si romperà ...
CMS

15

Come notato nei commenti di seguito, questo è specifico di Mozilla, ma puoi usare i blocchi "cattura condizionale". per esempio:

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

Questo dà qualcosa di più simile alla gestione delle eccezioni tipizzate usata in Java, almeno sintatticamente.


Combinalo con la risposta di CMS ed è perfetto.
Ates Goral

3
La cattura condizionale è qualcosa che non sapevo prima o di cui mi ero dimenticato. Grazie per avermi educato / ricordato! +1
Ates Goral,

12
Supportato solo da Firefox (dalla 2.0). Non analizza nemmeno in altri browser; ottieni solo errori di sintassi.
Crescent Fresh,

10
Sì, questa è un'estensione solo per Mozilla, non è nemmeno proposta per la standardizzazione. Essendo una funzionalità a livello di sintassi non c'è modo di annusarla e opzionalmente usarla neanche.
bobince

3
Inoltre, la soluzione proposta non è standard. Citazione dal [Mozilla's JavaScript Reference [( 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

Usando try-catch-finalmente.js , puoi chiamare la _tryfunzione con un callback anonimo, che chiamerà, e puoi concatenare .catchchiamate per rilevare errori specifici e una .finallychiamata per eseguire in entrambi i modi.

Esempio

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

Esempio con funzioni freccia moderne e letterali modello

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

2

Modulo per l'utilizzo in esportazione

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

Importa nello script:

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

Uso:

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

Codice chiamante esterno:

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

0

Non amavo nessuna di queste soluzioni, quindi ho creato la mia. Il try-catch-finalmente.js è piuttosto interessante tranne per il fatto che se dimentichi un piccolo trattino basso (_) prima del tentativo, il codice funzionerà comunque bene, ma nulla verrà mai catturato! Che schifo.

CatchFilter

Ho aggiunto un CatchFilter nel mio codice:

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

Ora posso filtrare

Ora posso filtrare come in 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.");
});

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

Ciao, benvenuto in StackOverflow. In che modo la tua risposta è migliore / più efficiente / ecc. Rispetto alle altre 5 risposte già pubblicate?
mjuarez
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.