Überprüfung auf Fehlertyp in JS

152

In JS scheint es nicht möglich zu sein, zu überprüfen, ob ein an eine Funktion übergebenes Argument tatsächlich vom Typ 'error' oder eine Instanz von Error ist.

Dies ist beispielsweise nicht gültig:

typeof err === 'error'

da es nur 6 mögliche Typen gibt (in Form von Strings):

Der Operator typeof gibt Typinformationen als Zeichenfolge zurück. Es gibt sechs mögliche Werte, die typeofzurückgegeben werden:

"number", "string", "boolean", "object", "function" und "undefined".

MSDN

Aber was ist, wenn ich einen einfachen Anwendungsfall wie diesen habe:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}

Was ist der beste Weg, um festzustellen, ob ein Argument eine Fehlerinstanz ist?

ist der instanceofBetreiber irgendeine Hilfe?

Alexander Mills
quelle
10
Ja, benutzeerr instanceof Error
colecmc
2
@colecmc Ist das nicht problematisch, wenn der Fehler möglicherweise von Code in einem Frame oder einem anderen Fenster herrührt? In diesem Fall gibt es verschiedene Prototyp-Fehlerobjekte, und die Instanz funktioniert nicht wie erwartet. (siehe developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Doin
@Doin, das glaube ich nicht. Es wird nur das eigentliche Fehlerobjekt validiert.
Colecmc
1
@colecmc, ich denke, Sie werden feststellen, dass Sie erhalten, wenn Sie einen Iframe eingeworfen err(sagen), ihn dann aber zur Übergabe an das übergeordnete Fenster übergeben (err instanceof Error) === false. Dies liegt daran, dass der Iframe und sein übergeordnetes Fenster unterschiedliche ErrorObjektprototypen haben. In ähnlicher Weise wird ein Objekt wie obj = {};will, wenn es an eine Funktion übergeben wird, die in einem anderen Fenster ausgeführt wird, yeild (obj instanceof Object)===false. (Selbst im schlimmsten Fall, wenn Sie im IE einen Verweis auf obj behalten, nachdem sein Fenster zerstört oder navigiert wurde, wird der Versuch, Objektprototyp-Fns wie aufzurufen obj.hasOwnProperty(), Fehler auslösen !)
Doin
Wie prüft man die Art des Fehlers? dh catch((err)=>{if (err === ENOENT)gibt ENOENT is not definedFehler zurück?
Oldboy

Antworten:

261

Sie können den instanceofOperator verwenden (siehe jedoch die Einschränkung unten!).

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Das Obige funktioniert nicht, wenn der Fehler in einem anderen Fenster / Frame / Iframe ausgelöst wurde als dort, wo die Überprüfung stattfindet. In diesem Fall gibt die instanceof ErrorPrüfung auch für ein ErrorObjekt false zurück . In diesem Fall ist das Enten-Tippen der einfachste Ansatz.

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

Allerdings Ente-Eingabe erzeugen kann zu Fehlalarmen kommen, wenn Sie nicht-Fehler - Objekte haben , die enthalten stackund messageEigenschaften.

Trott
quelle
1
@ AurélienRibon Es funktioniert gut mit einer ReferenceErrorInstanz. Sie überprüfen das globale ReferenceErrorObjekt. Versuchen try { foo } catch (e) { console.log(e instanceof Error) }Sie Folgendes : Es wird protokolliert true. Wenn Sie versuchen, das globale ReferenceErrorObjekt aus irgendeinem Grund zu überprüfen , können SieError.isPrototypeOf(ReferenceError)
Trott
1
@ AurélienRibon (Äh, ja, ich war mir auch nicht sicher, ob Sie sagten, dass dies mit einem Referenzfehler nicht funktioniert, was falsch ist, oder ob Sie nur darauf hinwiesen, dass dies mit dem globalen Referenzfehlerobjekt nicht funktioniert. Das ist absolut richtig, obwohl es mir schwer fällt, eine Situation zu finden, in der man das überprüfen würde, aber das sagt möglicherweise mehr über meine mangelnde Vorstellungskraft als über die Gültigkeit des Anwendungsfalls aus.
Trott
Haha, tut mir leid, ich war nur in einen seltsamen Fehler verwickelt, bei dem alle meine ReferenceErrorInstanzen keine Instanzen waren Error. Dies war auf einen Aufruf von vm.runInNewContext()in node zurückzuführen, bei dem alle Standardprototypen neu definiert werden. Alle meine Ergebnisse waren keine Instanzen von Standardobjekten. Ich habe in SO darüber gesucht und bin in diesen Thread gefallen :)
Aurelien Ribon
1
Sie können versuchenconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi
Wie überprüfen Sie, ob es sich um instanceofeine bestimmte Art von Fehler handelt?
Oldboy
24

Ich habe die ursprüngliche Frage gestellt - @ Trotts Antwort ist sicherlich die beste.

Da JS jedoch eine dynamische Sprache ist und es so viele JS-Laufzeitumgebungen gibt, kann der instanceofOperator insbesondere bei der Front-End-Entwicklung fehlschlagen, wenn Grenzen wie Iframes überschritten werden. Siehe: https://github.com/mrdoob/three.js/issues/5886

Wenn Sie mit dem Tippen von Enten einverstanden sind, sollte dies gut sein:

let isError = function(e){
 return e && e.stack && e.message;
}

Ich persönlich bevorzuge statisch typisierte Sprachen, aber wenn Sie eine dynamische Sprache verwenden, ist es am besten, eine dynamische Sprache als das zu akzeptieren, was sie ist, anstatt sie zu zwingen, sich wie eine statisch typisierte Sprache zu verhalten.

Wenn Sie etwas genauer werden möchten, können Sie dies tun:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }
Alexander Mills
quelle
3
Ich bevorzuge diese Version beim Schreiben einer Utility-Funktion oder Bibliothek. Es beschränkt Benutzer nicht auf einen bestimmten globalen Kontext und behandelt auch deserialisierte Fehler von JSON ordnungsgemäß.
Snickle
danke, ja in vielen fällen, wenn es wie ein fehler aussieht, können wir wie ein fehler behandeln. In einigen Fällen ist das Tippen von Enten völlig akzeptabel, in einigen Fällen ist es überhaupt nicht akzeptabel, in diesem Fall vollkommen in Ordnung.
Alexander Mills
Ich habe einige Fehler mit einem Debugger behoben, und Stapel und Nachricht scheinen wirklich die einzigen zwei nicht nativen Eigenschaften für Fehlerinstanzen zu sein.
Alexander Mills
1
@Trott Möglicherweise möchten Sie wissen, dass der instanceofOperator in einigen Fällen ausfällt. Weitere Informationen finden Sie im verlinkten Artikel.
Alexander Mills
1
Dies ist eigentlich die einfachste , so dass es mit den verschiedenen Arten von Fehlern arbeitet (dh Error, ReferenceError...). Und in meiner Umgebung instanceofscheitert das unter vielen Umständen kläglich.
Alexis Wilke
10
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Das einzige Problem dabei ist

myError instanceof Object // true

Eine Alternative dazu wäre die Verwendung der Konstruktoreigenschaft.

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

Obwohl zu beachten ist, dass diese Übereinstimmung sehr spezifisch ist, zum Beispiel:

myError.constructor === TypeError // false
Tom
quelle
2

Sie können Object.prototype.toStringdamit leicht überprüfen, ob es sich bei einem Objekt um ein Objekt handelt Error, das auch für verschiedene Frames funktioniert.

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));

hev1
quelle
1

Mit obj.constructor.name können Sie die "Klasse" eines Objekts https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes überprüfen

Beispielsweise

var error = new Error("ValidationError");
console.log(error.constructor.name);

In der obigen Zeile wird "Fehler" protokolliert, der der Klassenname des Objekts ist. Dies kann mit allen Klassen in Javascript verwendet werden, wenn die Klasse keine Eigenschaft verwendet, die den Namen "name" trägt.

persistent_poltergeist
quelle
Dies ist nicht zuverlässig, wenn Code minimiert und Fehlerunterklassen verwendet werden
felixfbecker
1

Vielen Dank an @Trott für Ihren Code. Ich habe nur denselben Code verwendet und ein Echtzeit-Arbeitsbeispiel zum Nutzen anderer hinzugefügt.

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>

Zabi Baig
quelle
0

Oder verwenden Sie dies für verschiedene Arten von Fehlern

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
Chris
quelle