Unterschiedliche Error-Typen in JavaScript – Einen von den nativen Error Typen verwenden – EvalError



Unterschiedliche Error-Typen in JavaScript – Einen von den nativen Error Typen verwenden – EvalError

0 0


JSErrorsTalk


On Github bdadam / JSErrorsTalk

Unterschiedliche Error-Typen in JavaScript

Adam Beres-Deak / bdadam.com / @bdadamm

Adam Beres-Deak

bdadam.com / @bdadamm

Wer hat Angst vor Exceptions?

Exceptions sind Freunde, nicht Feinde!

Agenda

Fehlerbehandlung in JavaScript Eingebaute und benutzerdefinierte Error-Typen Fehlerbehandlung in asynchron Funktionen Logging

1. try/catch/finally/throw

try {
    throw new Error('Something bad happened.');
}
catch(ex) {
    console.log(ex.name); // Error
    console.log(ex.message); // Something bad happened.
    console.log(ex.stack); // Error: Something bad happened.    at ...
}
finally {
    console.log('Finally always wins.');
}

3 mögliche Formen:

  • try - catch
  • try - finally
  • try - catch - finally

Das throw Statement

  • Es wirft eine Exception
  • Die Ausführung der aktuellen Funktion wird beendet,
  • und springt zum nächsten catch Block.
  • Falls es kein catch gibt, das Program wird beendet.

Was gibt diese Funktion zurück?

function trueOrFalse() {
    try {
        throw new Error('An error occured.');
    }
    catch(ex) {
        return false;
    }
    finally {
        return true;
    }
}

console.log(trueOrFalse()); // ????

Finally always wins!

function trueOrFalse() {
    try {
        throw new Error('An error occured.');
    }
    catch(ex) {
        return false;
    }
    finally {
        return true;
    }
}

console.log(trueOrFalse()); // true
warum gibt es finally überhaupt?

Finally always wins!

Der Code in finally Block läuft auch wenn:

  • return in try Block
  • Code in catch Block wirft eine Exception
  • kein catch Block

2. Fehlerbehandlung in asynchron Funktionen

Was passiert hier?

try{
    setTimeout(function() {
        throw new Error('An error occured.');
    }, 100);
} catch(ex) {
    console.log('An exception catched: ', ex);
}

Nicht das, was man auf dem ersten Blick erwarten würde

Uncaught Error: An error occured.

Was kann man dann tun?

Callback Funktionen statt throw

function doSomethingAsync(onSuccess, onError) {
    $.ajax(url, {
        success: onSuccess,
        error: onError
    });
}

doSomethingAsync(
    function() { console.log('success'); },
    function() { console.log('error'); }
);

Wie in Node.js

eine callback Funktion

fs.readFile('data.txt', function(errorOrNull, result) {
    if (errorOrNull) {
        // error handling
    }
});

Wie in Node.js /2

function doSomethingAsync(callback) {
    $.ajax(url, {
        success: function(data) { callback(null, data); },
        error: function() { callback(new Error('Network error.')); }
    });
}

Promises

doSomethingAsync()
    .then(onFulfilled, onRejected)
    .catch(function() { ... });

Promises /2

function doSomethingAsync() {
    return new Promise(function(resolve, reject) {
        $.ajax(url, {
            success: function(data) { resolve(data); },
            error: function() { reject(new Error('Network error')); }
        });
    });
}

3. Eingebaute und benutzerdefinierte Error-Typen

Theoretisch kann throw alles werfen

try {
    throw {};
    throw "Error";
    throw -1;
    throw function() {};
} catch(ex) {
    console.log(ex); // {} or "Error" or -1
}

Natives Error Objekt

throw new Error('Error message');
function throwsAnException() {
    throw new Error('Something bad happened.');
}

try {
    throwsAnException();
}
catch(ex) {
    console.log(error.name); // Error
    console.log(error.message); // Something bad happened.
    console.log(ex.stack);
}

Stacktrace (Error.stack)

Error: Something bad happened.
at throwsAnException (http://127.0.0.1:3000/:184:12)
at http://127.0.0.1:3000/:188:6
at http://127.0.0.1:3000/:193:5 (index):191

Exceptions sind Freunde nicht Feinde

  • Exceptions erzählen was passiert ist
  • Wo ist es schief gelaufen
  • Sie helfen beim Debuggen

Man sollte sinnvolle und sprechende Exceptions werfen

zumindest das message Property einer Ausnahme setzen

Was kann man noch besser machen?

Einen von den nativen Error Typen verwenden

Welche sind diese?

Error

throw new Error('Something bad happened.');

TypeError

function add(x, y) {
    if (isNaN(x) || isNaN(y)) {
        throw new TypeError('Arguments must be numbers.');
    }
}

URIError

function goToUrl(url) {
    if (url.indexOf('example.com') < 0) {
        throw new URIError('Argument must be a URI \
            on the example.com domain.');
    }
}

RangeError

function checkAge(age) {
    if (age > 150 || age < 0) {
        throw new RangeError('A valid age must be specified.');
    }
}

EvalError

SyntaxError

ReferenceError

Benutzerdefinierte Error Types

function MyError(message) {
    this.message = message;
    var stack = (new Error()).stack;
    if (stack) { this.stack = stack; }
}

MyError.prototype = new Error();
MyError.constructor = MyError;
MyError.prototype.name = 'MyError';

try {
    throw new MyError('Error message.');
} catch(ex) {
    console.log(ex instanceof Error); // true
    console.log(ex instanceof MyError); // true
}

Unterschiedliche Behandlung je nach Error Typ

z.B. in C#:

try {...}
catch (ArgumentException ex) { ... }
catch (FileNotFoundException ex) { ... }

Der Standard Weg

try { ... }
catch(ex) {
    if (ex instanceof URIError) { ... }
    else if (ex instanceof TypeError) { ... }
    else if (ex instanceof MyCustomError) { ... }
}

Der Firefox Weg

try {
    myroutine(); // may throw some exceptions
}
catch (e if e instanceof TypeError) { ... }
catch (e if e instanceof RangeError) { ... }
catch (e) {
    logMyErrors(e); // pass exception object to error handler
}

mehr Infos auf MDN

Was für Fehler können überhaupt auftreten?

  • Handled exceptions: wir sind vorbereitet, dass der Code Exceptions werfen kann (TypeError, RangeError, falscher Userinput usw.).

  • Aber was passiert mit unerwarteten Fehlern? Wie z.B.: Programmfehler, Logikfehler oder fehlende Ressource (z.B. Netzwerkproblem)

4. Error Logging

Wie sollte man unhandled Exceptions loggen?

window.onerror = function(message, url, lineNumber) {
    // log error
};
var onError = window.onerror;
window.onerror = function(message, url, lineNumber) {
    // log error

    // then call the other event handler if any
    onError && onError.apply(window, arguments);
};
Vorteile Nachteile cross-browser kein Zugriff auf dem aktuellen Error Objekt einfach kein Stacktrace

Für neuere Browser

window.addEventListener('error', function(errorEvent) {
    console.log(errorEvent);
    console.log(errorEvent.error);
    console.log(errorEvent.error.message);
    console.log(errorEvent.error.stack);
    console.log(errorEvent.lineno);
});
Vorteile Nachteile Zugriff auf dem Error Objekt nicht cross-browser (ab IE10) Stacktrace

Was kann man loggen?

Was kann man loggen?

  • ein Fehler ist aufgetreten (unhandled exception)
  • auf welcher Seite
  • wo (Skript-URL, Zeile, domain: extern/intern)
  • Browser, OS (User Agent)
  • Client IP

Wie kann man die Fehler loggen?

Google Analytics oder anderes Tracking Tool

window.onerror = function(message, url, lineNumber) {
    _gaq.push([
        '_trackEvent',
        'JavaScript Error',
        message,
        url.indexOf('example.com/') > 0 ? 'internal' : 'external',
        true
    ]);
};
Vorteile Nachteile Nur clientseitig Daten sind begrenzt (paar 100 Zeichen, je nach Tool) Alerts sind einfach einzurichten

Access log

window.onerror = function(message, url, lineNumber) {
    var data = {
        msg: message,
        url: url,
        internal: (url.indexOf('example.com/') > 0)
    };

    new Image().src = '/path/to/logger?data=' + JSON.stringify(data);
};
Vorteile Nachteile Monitoring ist einfach (z.B. Splunk) man braucht Monitoring für Alerting (serverseitig) Begrenzung erst bei 2k oder 8k Zeichen (max. URL Länge)
Wir bei AutoScout24 haben den Weg mit dem Access Log gewählt. Zum Monitoring benutzen wir Splunk.

Herausforderungen

  • Browserunterschiede (Sprache im IE)
  • Wie trennt man die wichtigen Log-Einträge von den unwichtigen?
  • Browser Extensions können auch Exceptions werfen (und sie fliessen in die Logs rein)
  • Sind die konkrete Fehler interessant, oder eher die Anzahl von Ereignissen?

Diese Probleme sind schon mehr oder weniger gelöst

  • es gibt mehrere Services
  • sie haben schon die Expertise, diese Herausforderungen zu bekämpfen
  • AutoScout24 ist grad am Evaluieren

Zusammenfassung

Was haben wir gesehen?

  • Wie man Fehler in JavaScript behandelt
  • Auch bei asynchronen Funtionen
  • Wie kann man für sinnvolle Fehlermeldungen sorgen
  • Was man tun kann, um clientseitige Fehler zu entdecken
0