Umgang mit bestimmten Fehlern in JavaScript (Ausnahmen denken)


111

Wie würden Sie verschiedene Arten von Fehlern implementieren, damit Sie bestimmte Fehler abfangen und andere in die Luft sprudeln lassen können?

Eine Möglichkeit, dies zu erreichen, besteht darin, den Prototyp des ErrorObjekts zu ändern :

Error.prototype.sender = "";


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

    e.sender = "specific";

    throw e;
}

Fangspezifischer Fehler:

try
{
    throwSpecificError();
}

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

    // handle specific error
}


Habt ihr Alternativen?

Antworten:


158

Um benutzerdefinierte Ausnahmen zu erstellen, können Sie vom Fehlerobjekt erben:

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

Ein minimalistischer Ansatz, ohne von Error zu erben, könnte darin bestehen, ein einfaches Objekt mit einem Namen und einer Nachrichteneigenschaft auszulösen:

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
Das Erben von Errorhat Probleme. Siehe stackoverflow.com/questions/1382107/…
Crescent Fresh

5
Das Problem mit diesem Code } catch (e) { if (e.name == 'SpecificError') { // specific error } else { throw e; // let others bubble up } }ist, dass er in IE7 nicht funktioniert und den Fehler "Ausnahme ausgelöst und nicht abgefangen" auslöst. Es folgt die äußerst dumme (wie immer) Erklärung von msdn: "Sie haben eine throw-Anweisung eingefügt, die jedoch nicht in einem try-Block enthalten war, oder es gab keinen zugehörigen catch-Block, um den Fehler abzufangen. Ausnahmen werden aus dem try-Block ausgelöst Verwenden der throw-Anweisung und Abfangen außerhalb des try-Blocks mit einer catch-Anweisung. "
Eugene Kuzmenko

1
Nun, Microsofts C # behandelt Fehler sicherlich besser als Javascript: P. Mozzilla hat Firefox so etwas hinzugefügt. Es ist zwar nicht im Ecmascript-Standard enthalten, nicht einmal in ES6, aber sie erklären auch, wie man es anpasst, obwohl es nicht so prägnant ist. Grundsätzlich wie oben, aber mit instanceOf. Überprüfen Sie hier
Bart

In Javascript können Sie alles werfen, was Sie wollen, sei es eine einfache Zeichenfolge, eine Zahl (denken Sie an einen Fehlercode) oder ein vollständig qualifiziertes Objekt. Süss!
Abraham Brookes

1
@LuisNell, Wenn Sie sich mein Codebeispiel genau ansehen, werden Sie feststellen, dass ich nicht vorgeschlagen habe, die nameEigenschaft der Konstruktorfunktion zu verwenden. Ich schlug vor, ein maßgeschneidertes Objekt mit einer nameEigenschaft zu werfen , die nicht kaputt geht ...
CMS

15

Wie in den Kommentaren unten erwähnt, ist dies Mozilla-spezifisch, Sie können jedoch "bedingte Fang" -Blöcke verwenden. z.B:

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

Dies ähnelt zumindest syntaktisch eher der in Java verwendeten typisierten Ausnahmebehandlung.


Kombinieren Sie mit der Antwort von CMS und es ist perfekt.
Ates Goral

3
Bedingter Fang ist etwas, das ich entweder vorher nicht wusste oder vergessen habe. Danke, dass du mich erzogen / daran erinnert hast! +1
Ates Goral

12
Wird nur von Firefox unterstützt (seit 2.0). Es wird nicht einmal in anderen Browsern analysiert. Sie erhalten nur Syntaxfehler.
Crescent Fresh

10
Ja, dies ist eine reine Mozilla-Erweiterung, die nicht einmal zur Standardisierung vorgeschlagen wird. Da es sich um eine Funktion auf Syntaxebene handelt, gibt es keine Möglichkeit, daran zu riechen und sie optional zu verwenden.
Bobince

3
Hinzu kommt, dass die vorgeschlagene Lösung nicht dem Standard entspricht. Zitat aus der [Mozillas JavaScript-Referenz [( 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

Mit try-catch-finally.js können Sie die _tryFunktion mit einem anonymen Rückruf aufrufen, den sie .catchaufruft , und Sie können Aufrufe verketten , um bestimmte Fehler abzufangen , und einen .finallyAufruf, um sie in beide Richtungen auszuführen.

Beispiel

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

Beispiel mit modernen Pfeilfunktionen und Vorlagenliteralen

_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

Modul für den Export

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

In Skript importieren:

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

Verwenden:

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

Anrufcode extern:

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

Ich habe keine dieser Lösungen geliebt, also habe ich meine eigene gemacht. Die try-catch-finally.js ist ziemlich cool, außer dass, wenn Sie vor dem Versuch einen kleinen Unterstrich (_) vergessen, der Code immer noch einwandfrei läuft, aber nie etwas gefangen wird! Yuck.

CatchFilter

Ich habe meinem Code einen CatchFilter hinzugefügt:

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

Jetzt kann ich filtern

Jetzt kann ich wie in C # oder Java filtern:

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

Hallo, willkommen bei StackOverflow. Wie ist Ihre Antwort besser / effizienter / usw. aus den anderen 5 bereits veröffentlichten Antworten?
Mjuarez
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.